diff --git a/openbis_ng_ui/src/js/components/common/grid/GridHeaderLabel.jsx b/openbis_ng_ui/src/js/components/common/grid/GridHeaderLabel.jsx
index f659726208c540905079de95a5c7cb6f43dcf696..96e1daab89afc676e799e92b0d5d24aeb739ceaa 100644
--- a/openbis_ng_ui/src/js/components/common/grid/GridHeaderLabel.jsx
+++ b/openbis_ng_ui/src/js/components/common/grid/GridHeaderLabel.jsx
@@ -14,10 +14,10 @@ const styles = theme => ({
 class GridHeaderLabel extends React.PureComponent {
   constructor(props) {
     super(props)
-    this.handleSortChange = this.handleSortChange.bind(this)
+    this.handleClick = this.handleClick.bind(this)
   }
 
-  handleSortChange() {
+  handleClick() {
     const { column, onSortChange } = this.props
     if (onSortChange) {
       onSortChange(column)
@@ -36,7 +36,7 @@ class GridHeaderLabel extends React.PureComponent {
             <TableSortLabel
               active={sort === column.field}
               direction={sortDirection}
-              onClick={this.handleSortChange}
+              onClick={this.handleClick}
             >
               {column.label}
             </TableSortLabel>
diff --git a/openbis_ng_ui/src/js/components/common/grid/GridRow.jsx b/openbis_ng_ui/src/js/components/common/grid/GridRow.jsx
index 365ee9898f22f864adf1c3cbb5a4e56334914f0d..865bd76121a884aaf39b46c479c553bc871eccc6 100644
--- a/openbis_ng_ui/src/js/components/common/grid/GridRow.jsx
+++ b/openbis_ng_ui/src/js/components/common/grid/GridRow.jsx
@@ -17,10 +17,10 @@ const styles = theme => ({
 class GridRow extends React.PureComponent {
   constructor(props) {
     super(props)
-    this.handleOnClick = this.handleOnClick.bind(this)
+    this.handleClick = this.handleClick.bind(this)
   }
 
-  handleOnClick() {
+  handleClick() {
     const { onClick, row } = this.props
     if (onClick) {
       onClick(row)
@@ -35,7 +35,7 @@ class GridRow extends React.PureComponent {
     return (
       <TableRow
         key={row.id}
-        onClick={this.handleOnClick}
+        onClick={this.handleClick}
         hover={true}
         selected={selected}
         classes={{
diff --git a/openbis_ng_ui/srcTest/js/common/fixture.js b/openbis_ng_ui/srcTest/js/common/fixture.js
index d51b13505a8c89fedc553d705d91184eec295533..c40347d0ce8aff6af3c06e982009422092bd220c 100644
--- a/openbis_ng_ui/srcTest/js/common/fixture.js
+++ b/openbis_ng_ui/srcTest/js/common/fixture.js
@@ -97,21 +97,36 @@ ANOTHER_MATERIAL_TYPE_DTO.setCode('ANOTHER_MATERIAL_TYPE')
 
 const TEST_TERM_1_DTO = new openbis.VocabularyTerm()
 TEST_TERM_1_DTO.setCode('TERM_1')
+TEST_TERM_1_DTO.setLabel('Label 1')
+TEST_TERM_1_DTO.setDescription('Description 1')
+TEST_TERM_1_DTO.setOfficial(true)
 
 const TEST_TERM_2_DTO = new openbis.VocabularyTerm()
 TEST_TERM_2_DTO.setCode('TERM_2')
+TEST_TERM_2_DTO.setLabel('Label 2')
+TEST_TERM_2_DTO.setDescription('Description 2')
+TEST_TERM_2_DTO.setOfficial(true)
 
 const TEST_TERM_3_DTO = new openbis.VocabularyTerm()
 TEST_TERM_3_DTO.setCode('TERM_3')
+TEST_TERM_3_DTO.setLabel('Label 3')
+TEST_TERM_3_DTO.setDescription('Description 3')
+TEST_TERM_3_DTO.setOfficial(true)
 
 const TEST_TERM_4_DTO = new openbis.VocabularyTerm()
 TEST_TERM_4_DTO.setCode('TERM_4')
+TEST_TERM_4_DTO.setLabel('Label 4')
+TEST_TERM_4_DTO.setOfficial(false)
 
 const TEST_TERM_5_DTO = new openbis.VocabularyTerm()
 TEST_TERM_5_DTO.setCode('TERM_5')
+TEST_TERM_5_DTO.setLabel('Label 5')
+TEST_TERM_5_DTO.setOfficial(false)
 
 const TEST_TERM_6_DTO = new openbis.VocabularyTerm()
 TEST_TERM_6_DTO.setCode('TERM_6')
+TEST_TERM_6_DTO.setLabel('Label 6')
+TEST_TERM_6_DTO.setOfficial(false)
 
 const TEST_VOCABULARY_DTO = new openbis.Vocabulary()
 TEST_VOCABULARY_DTO.setCode('TEST_VOCABULARY')
@@ -151,5 +166,11 @@ export default {
   TEST_MATERIAL_TYPE_DTO,
   ANOTHER_MATERIAL_TYPE_DTO,
   TEST_VOCABULARY_DTO,
-  ANOTHER_VOCABULARY_DTO
+  ANOTHER_VOCABULARY_DTO,
+  TEST_TERM_1_DTO,
+  TEST_TERM_2_DTO,
+  TEST_TERM_3_DTO,
+  TEST_TERM_4_DTO,
+  TEST_TERM_5_DTO,
+  TEST_TERM_6_DTO
 }
diff --git a/openbis_ng_ui/srcTest/js/components/common/form/wrapper/FilterFieldWrapper.js b/openbis_ng_ui/srcTest/js/components/common/form/wrapper/FilterFieldWrapper.js
index e8292e8ce2307d57075387b2a5d3996dbb143f64..bff564e3ab2a76490520f535d3d0ce4242b0af90 100644
--- a/openbis_ng_ui/srcTest/js/components/common/form/wrapper/FilterFieldWrapper.js
+++ b/openbis_ng_ui/srcTest/js/components/common/form/wrapper/FilterFieldWrapper.js
@@ -23,7 +23,8 @@ export default class FilterFieldWrapper extends BaseWrapper {
   toJSON() {
     if (this.wrapper.exists()) {
       return {
-        value: this.getValue()
+        value: this.getValue(),
+        clearIcon: this.getClearIcon().toJSON()
       }
     } else {
       return null
diff --git a/openbis_ng_ui/srcTest/js/components/common/form/wrapper/IconWrapper.js b/openbis_ng_ui/srcTest/js/components/common/form/wrapper/IconWrapper.js
index 6a2ae668638934ad559b9dc849d4497843423664..54c3d2e3933d55c74aea854469ac5d3d7de39b24 100644
--- a/openbis_ng_ui/srcTest/js/components/common/form/wrapper/IconWrapper.js
+++ b/openbis_ng_ui/srcTest/js/components/common/form/wrapper/IconWrapper.js
@@ -7,4 +7,12 @@ export default class IconWrapper extends BaseWrapper {
       preventDefault: function () {}
     })
   }
+
+  toJSON() {
+    if (this.wrapper.exists()) {
+      return {}
+    } else {
+      return null
+    }
+  }
 }
diff --git a/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridColumnLabelWrapper.js b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridColumnLabelWrapper.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b67986a30fbd7c8a59656a1e8abab50643a7276
--- /dev/null
+++ b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridColumnLabelWrapper.js
@@ -0,0 +1,19 @@
+import BaseWrapper from '@srcTest/js/components/common/wrapper/BaseWrapper.js'
+
+export default class GridColumnLabelWrapper extends BaseWrapper {
+  getValue() {
+    return this.wrapper.text()
+  }
+
+  click() {
+    this.wrapper.instance().handleClick()
+  }
+
+  toJSON() {
+    if (this.wrapper.exists()) {
+      return this.getValue()
+    } else {
+      return null
+    }
+  }
+}
diff --git a/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridColumnWrapper.js b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridColumnWrapper.js
new file mode 100644
index 0000000000000000000000000000000000000000..1af09e28bb30bfdf38dd9f481de41abe9a33b987
--- /dev/null
+++ b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridColumnWrapper.js
@@ -0,0 +1,45 @@
+import BaseWrapper from '@srcTest/js/components/common/wrapper/BaseWrapper.js'
+import FilterFieldWrapper from '@srcTest/js/components/common/form/wrapper/FilterFieldWrapper.js'
+import GridColumnLabelWrapper from '@srcTest/js/components/common/grid/wrapper/GridColumnLabelWrapper.js'
+
+export default class GridColumnWrapper extends BaseWrapper {
+  constructor(column, labelWrapper, filterWrapper, sortWrapper) {
+    super(null)
+    this.column = column
+    this.labelWrapper = labelWrapper
+    this.filterWrapper = filterWrapper
+    this.sortWrapper = sortWrapper
+  }
+
+  getField() {
+    return this.column.field
+  }
+
+  getLabel() {
+    return new GridColumnLabelWrapper(this.labelWrapper)
+  }
+
+  getFilter() {
+    return new FilterFieldWrapper(this.filterWrapper)
+  }
+
+  getSort() {
+    const active = this.sortWrapper.prop('active')
+    const direction = this.sortWrapper.prop('direction')
+
+    if (active) {
+      return direction
+    } else {
+      return null
+    }
+  }
+
+  toJSON() {
+    return {
+      field: this.getField(),
+      label: this.getLabel().toJSON(),
+      filter: this.getFilter().toJSON(),
+      sort: this.getSort()
+    }
+  }
+}
diff --git a/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridRowWrapper.js b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridRowWrapper.js
new file mode 100644
index 0000000000000000000000000000000000000000..e0da9e3cc011afb7fb257ada78651c8979a2b5dd
--- /dev/null
+++ b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridRowWrapper.js
@@ -0,0 +1,35 @@
+import BaseWrapper from '@srcTest/js/components/common/wrapper/BaseWrapper.js'
+import TableCell from '@material-ui/core/TableCell'
+
+export default class GridRowWrapper extends BaseWrapper {
+  getValues() {
+    const columns = this.wrapper.prop('columns')
+    const values = {}
+
+    this.findComponent(TableCell).forEach((cell, index) => {
+      const column = columns[index]
+      values[column.field] = this.getStringValue(cell.text().trim())
+    })
+
+    return values
+  }
+
+  getSelected() {
+    return this.getBooleanValue(this.wrapper.prop('selected'))
+  }
+
+  click() {
+    this.wrapper.instance().handleClick()
+  }
+
+  toJSON() {
+    if (this.wrapper.exists()) {
+      return {
+        values: this.getValues(),
+        selected: this.getSelected()
+      }
+    } else {
+      return null
+    }
+  }
+}
diff --git a/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridWrapper.js b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridWrapper.js
index f32b1232c89aaaa4f9127984894f798377bce910..792633f1b8f51a7526cf96467c512560433d0291 100644
--- a/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridWrapper.js
+++ b/openbis_ng_ui/srcTest/js/components/common/grid/wrapper/GridWrapper.js
@@ -1,54 +1,41 @@
 import BaseWrapper from '@srcTest/js/components/common/wrapper/BaseWrapper.js'
-import TableCell from '@material-ui/core/TableCell'
 import TableSortLabel from '@material-ui/core/TableSortLabel'
+import FilterField from '@src/js/components/common/form/FilterField.jsx'
 import GridHeaderLabel from '@src/js/components/common/grid/GridHeaderLabel.jsx'
-import GridHeaderFilter from '@src/js/components/common/grid/GridHeaderFilter.jsx'
 import GridRow from '@src/js/components/common/grid/GridRow.jsx'
+import GridRowWrapper from '@srcTest/js/components/common/grid/wrapper/GridRowWrapper.js'
+import GridColumnWrapper from '@srcTest/js/components/common/grid/wrapper/GridColumnWrapper.js'
 
 export default class GridWrapper extends BaseWrapper {
   getColumns() {
     const columns = this.wrapper.prop('columns')
 
-    const sortLabels = this.findComponent(TableSortLabel)
     const labels = this.findComponent(GridHeaderLabel)
-    const filters = this.findComponent(GridHeaderFilter)
+    const filters = this.findComponent(FilterField)
+    const sorts = this.findComponent(TableSortLabel)
 
     return columns.map((column, index) => {
-      const label = labels.at(index).text()
-      const filter = filters.at(index).text()
-      const sort = sortLabels.at(index).prop('active')
-      const sortDirection = sortLabels.at(index).prop('direction')
+      const label = labels.at(index)
+      const filter = filters.at(index)
+      const sort = sorts.at(index)
 
-      return {
-        field: this.getStringValue(column.field),
-        label: this.getStringValue(label),
-        filter: this.getStringValue(filter),
-        sort: this.getBooleanValue(sort),
-        sortDirection: this.getStringValue(sortDirection)
-      }
+      return new GridColumnWrapper(column, label, filter, sort)
     })
   }
 
   getRows() {
-    const columns = this.wrapper.prop('columns')
-
-    return this.findComponent(GridRow).map(row => {
-      const values = {}
-
-      this.findComponent(TableCell, row).forEach((cell, index) => {
-        const column = columns[index]
-        values[column.field] = this.getStringValue(cell.text())
-      })
-
-      return values
+    const rows = []
+    this.findComponent(GridRow).forEach(rowWrapper => {
+      rows.push(new GridRowWrapper(rowWrapper))
     })
+    return rows
   }
 
   toJSON() {
     if (this.wrapper.exists()) {
       return {
-        columns: this.getColumns(),
-        rows: this.getRows()
+        columns: this.getColumns().map(row => row.toJSON()),
+        rows: this.getRows().map(row => row.toJSON())
       }
     } else {
       return null
diff --git a/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js b/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js
index 758b77784fe9412b4471295fad98ff899d311e04..b7feb913e2f5fe00fc98d053eafcb0c91109cf7f 100644
--- a/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js
+++ b/openbis_ng_ui/srcTest/js/components/types/form/VocabularyFormComponent.test.js
@@ -27,6 +27,7 @@ beforeEach(() => {
 describe('VocabularyFormComponent', () => {
   test('load new', testLoadNew)
   test('load existing', testLoadExisting)
+  test('select term', testSelectTerm)
 })
 
 async function testLoadNew() {
@@ -84,30 +85,44 @@ async function testLoadExisting() {
       {
         field: 'code.value',
         label: 'Code',
-        filter: null,
-        sort: false
+        filter: {
+          value: null
+        },
+        sort: null
       },
       {
         field: 'label.value',
         label: 'Label',
-        filter: null,
-        sort: false
+        filter: {
+          value: null
+        },
+        sort: null
       },
       {
         field: 'description.value',
         label: 'Description',
-        filter: null,
-        sort: false
+        filter: {
+          value: null
+        },
+        sort: null
       },
       {
         field: 'official.value',
         label: 'Official',
-        filter: null,
-        sort: false
+        filter: {
+          value: null
+        },
+        sort: null
       }
     ],
     rows: fixture.TEST_VOCABULARY_DTO.terms.map(term => ({
-      'code.value': term.getCode()
+      values: {
+        'code.value': term.getCode(),
+        'label.value': term.getLabel(),
+        'description.value': term.getDescription(),
+        'official.value': String(term.isOfficial())
+      },
+      selected: false
     }))
   }
 
@@ -191,6 +206,74 @@ async function testLoadExisting() {
   })
 }
 
+async function testSelectTerm() {
+  const form = await mountExisting()
+
+  form.getGrid().getRows()[1].click()
+  await form.update()
+
+  form.getButtons().getEdit().click()
+  await form.update()
+
+  form.expectJSON({
+    grid: {
+      rows: [
+        { selected: false },
+        { selected: true },
+        { selected: false },
+        { selected: false },
+        { selected: false },
+        { selected: false }
+      ]
+    },
+    parameters: {
+      term: {
+        title: 'Term',
+        code: {
+          label: 'Code',
+          value: fixture.TEST_TERM_2_DTO.getCode(),
+          enabled: false,
+          mode: 'edit'
+        },
+        label: {
+          label: 'Label',
+          value: fixture.TEST_TERM_2_DTO.getLabel(),
+          enabled: true,
+          mode: 'edit'
+        },
+        description: {
+          label: 'Description',
+          value: fixture.TEST_TERM_2_DTO.getDescription(),
+          enabled: true,
+          mode: 'edit'
+        },
+        official: {
+          label: 'Official',
+          value: fixture.TEST_TERM_2_DTO.isOfficial(),
+          enabled: false,
+          mode: 'edit'
+        }
+      }
+    },
+    buttons: {
+      addTerm: {
+        enabled: true
+      },
+      removeTerm: {
+        enabled: true
+      },
+      save: {
+        enabled: true
+      },
+      cancel: {
+        enabled: true
+      },
+      edit: null,
+      message: null
+    }
+  })
+}
+
 async function mountNew() {
   return await common.mount({
     type: objectTypes.NEW_VOCABULARY_TYPE
diff --git a/openbis_ng_ui/srcTest/js/components/types/form/wrapper/VocabularyFormParametersTermWrapper.js b/openbis_ng_ui/srcTest/js/components/types/form/wrapper/VocabularyFormParametersTermWrapper.js
new file mode 100644
index 0000000000000000000000000000000000000000..4dd1f09d2acba4f470103553baea921042fad28f
--- /dev/null
+++ b/openbis_ng_ui/srcTest/js/components/types/form/wrapper/VocabularyFormParametersTermWrapper.js
@@ -0,0 +1,41 @@
+import CheckboxField from '@src/js/components/common/form/CheckboxField.jsx'
+import TextField from '@src/js/components/common/form/TextField.jsx'
+import CheckboxFieldWrapper from '@srcTest/js/components/common/form/wrapper/CheckboxFieldWrapper.js'
+import TextFieldWrapper from '@srcTest/js/components/common/form/wrapper/TextFieldWrapper.js'
+import VocabularyFormParametersCommonWrapper from './VocabularyFormParametersCommonWrapper.js'
+
+export default class VocabularyFormParametersTermWrapper extends VocabularyFormParametersCommonWrapper {
+  getCode() {
+    return new TextFieldWrapper(
+      this.findComponent(TextField).filter({ name: 'code' })
+    )
+  }
+
+  getLabel() {
+    return new TextFieldWrapper(
+      this.findComponent(TextField).filter({ name: 'label' })
+    )
+  }
+
+  getDescription() {
+    return new TextFieldWrapper(
+      this.findComponent(TextField).filter({ name: 'description' })
+    )
+  }
+
+  getOfficial() {
+    return new CheckboxFieldWrapper(
+      this.findComponent(CheckboxField).filter({ name: 'official' })
+    )
+  }
+
+  toJSON() {
+    return {
+      ...super.toJSON(),
+      code: this.getCode().toJSON(),
+      label: this.getLabel().toJSON(),
+      description: this.getDescription().toJSON(),
+      official: this.getOfficial().toJSON()
+    }
+  }
+}
diff --git a/openbis_ng_ui/srcTest/js/components/types/form/wrapper/VocabularyFormParametersWrapper.js b/openbis_ng_ui/srcTest/js/components/types/form/wrapper/VocabularyFormParametersWrapper.js
index 2fc76d7a3d74d4d76bd50de1ff664435ed9356d0..4929f018f9c1c8cce67d7544d79bad2180978171 100644
--- a/openbis_ng_ui/srcTest/js/components/types/form/wrapper/VocabularyFormParametersWrapper.js
+++ b/openbis_ng_ui/srcTest/js/components/types/form/wrapper/VocabularyFormParametersWrapper.js
@@ -1,6 +1,8 @@
 import BaseWrapper from '@srcTest/js/components/common/wrapper/BaseWrapper.js'
 import VocabularyFormParametersVocabulary from '@src/js/components/types/form/VocabularyFormParametersVocabulary.jsx'
 import VocabularyFormParametersVocabularyWrapper from './VocabularyFormParametersVocabularyWrapper.js'
+import VocabularyFormParametersTerm from '@src/js/components/types/form/VocabularyFormParametersTerm.jsx'
+import VocabularyFormParametersTermWrapper from './VocabularyFormParametersTermWrapper.js'
 
 export default class VocabularyFormParametersWrapper extends BaseWrapper {
   getVocabulary() {
@@ -9,9 +11,16 @@ export default class VocabularyFormParametersWrapper extends BaseWrapper {
     )
   }
 
+  getTerm() {
+    return new VocabularyFormParametersTermWrapper(
+      this.findComponent(VocabularyFormParametersTerm)
+    )
+  }
+
   toJSON() {
     return {
-      vocabulary: this.getVocabulary().toJSON()
+      vocabulary: this.getVocabulary().toJSON(),
+      term: this.getTerm().toJSON()
     }
   }
 }