Skip to main content
Default Gray Amethyst

Datagrid

<mo-datagrid> | MODatagrid
Since 1.4 stable

Data grid is a component to display, organize and edit data in table form of rows and columns.

The datagrid implementation in Modes UI is based on ag-grid (community). Their documentation pages provides exhaustive documentation on customization options beyond those available here. Note that some documentation and features are limited to the enterprise license, which is not available here in Modes UI.


Randomize data
<mo-datagrid id="first-example"></mo-datagrid>
<br/>
<mo-button id="randomize">Randomize data</mo-button>

<script>
  const grid = document.querySelector('#first-example');
  const btn = document.querySelector('#randomize');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);

  btn.addEventListener('click', () => {
    grid.grid.setGridOption('rowData', createMockData(30));
  })

  const gridOptions = {
    columnDefs: [
      {
        headerName: 'Make',
        field: 'make',
        sortable: true,
        filter: true
      },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
    ],
    rowData: rowData
  };
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000)
    });
  });
  return data;
};
const rowData = createMockData(30);

const gridOptions = {
  columnDefs: [
    {
      headerName: 'Make',
      field: 'make',
      sortable: true,
      filter: true
    },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
  ],
  rowData: rowData
};

const App = () => <MODatagrid options={gridOptions}></MODatagrid>;

Examples

With default column definitions and custom size

The columns do not have to have individual configuration, and instead they will use a global default if it is defined in the options. The default height of a grid is 350px and the default width is the full width of the container. The height property must be a static value.

This example features re-sizable and editable columns, with “floating” filter boxes.

<mo-datagrid id="default"></mo-datagrid>

<script>
  const grid = document.querySelector('#default');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);
  const gridOptions = {
    defaultColDef: {
      editable: true,
      resizable: true,
      minWidth: 100,
      flex: 1,
      filter: true,
      floatingFilter: true,
      suppressHeaderMenuButton: true
    },
    columnDefs: [
      { headerName: 'Make', field: 'make' },
      { headerName: 'Model', field: 'model' },
      { headerName: 'Price', field: 'price', type: 'numberColumn', resizable: false }
    ],
    rowData: rowData
  };
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000)
    });
  });
  return data;
};
const rowData = createMockData(30);

const gridOptions = {
  defaultColDef: {
    editable: true,
    resizable: true,
    minWidth: 100,
    flex: 1,
    filter: true,
    floatingFilter: true,
    suppressHeaderMenuButton: true
  },
  columnDefs: [
    { headerName: 'Make', field: 'make' },
    { headerName: 'Model', field: 'model' },
    { headerName: 'Price', field: 'price', type: 'numberColumn', resizable: false }
  ],
  rowData: rowData
};

const App = () => <MODatagrid options={gridOptions}></MODatagrid>;

Different filtering types

Filtering for dates and numbers has some different options than filtering for strings. This example shows how to compare and format dates properly.

<mo-datagrid id="filters"></mo-datagrid>

<script>
  const grid = document.querySelector('#filters');
  const picker = document.querySelector('#picker');
  function randomDate(start, end) {
    return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
  }
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000),
        date: randomDate(new Date(2022, 0, 1), new Date())
      });
    });
    return data;
  }
  const rowData = createMockData(30);
  function dateFormatter(date) {
    return date.toLocaleDateString('en-us', {
      year: 'numeric',
      month: 'short',
      day: 'numeric'
    });
  }
  const gridOptions = {
    defaultColDef: {
      editable: true,
      resizable: true,
      minWidth: 100,
      flex: 1,
      filter: true
    },
    columnDefs: [
      { headerName: 'Make', field: 'make' },
      { headerName: 'Model', field: 'model' },
      { headerName: 'Price', field: 'price', filter: 'agNumberColumnFilter', type: 'numberColumn' },
      {
        headerName: 'Posting date',
        minWidth: 200,
        field: 'date',
        type: 'dateColumn',
        filter: 'agDateColumnFilter',
        valueFormatter: params => dateFormatter(params.data.date),
        filterParams: {
          filterOptions: [
            'equals',
            'notEqual',
            {
              displayKey: 'before',
              displayName: 'Before',
              predicate: ([filterValue], cellValue) => cellValue == null || cellValue < filterValue
            },
            {
              displayKey: 'after',
              displayName: 'After',
              predicate: ([filterValue], cellValue) => cellValue == null || cellValue > filterValue
            },
            {
              displayKey: 'betweenExclusive',
              displayName: 'Between (Exclusive)',
              predicate: ([fv1, fv2], cellValue) => cellValue == null || (fv1 < cellValue && fv2 > cellValue),
              numberOfInputs: 2
            },
            {
              displayKey: 'betweenInclusive',
              displayName: 'Between (Inclusive)',
              predicate: ([fv1, fv2], cellValue) => cellValue == null || (fv1 <= cellValue && fv2 >= cellValue),
              numberOfInputs: 2
            }
          ],
          comparator: (filterLocalDateAtMidnight, cellDate) => {
            if (cellDate > filterLocalDateAtMidnight) {
              return 1;
            } else if (cellDate < filterLocalDateAtMidnight) {
              return -1;
            }
            return 0;
          }
        }
      }
    ],
    rowData: rowData
  };
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const randomDate = (start, end) => {
  return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
};
const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000),
      date: randomDate(new Date(2022, 0, 1), new Date())
    });
  });
  return data;
};
const rowData = createMockData(30);
const dateFormatter = date => {
  return date.toLocaleDateString('en-us', {
    year: 'numeric',
    month: 'short',
    day: 'numeric'
  });
};
const gridOptions = {
  defaultColDef: {
    editable: true,
    resizable: true,
    minWidth: 100,
    flex: 1,
    filter: true
  },
  columnDefs: [
    { headerName: 'Make', field: 'make' },
    { headerName: 'Model', field: 'model' },
    { headerName: 'Price', field: 'price', filter: 'agNumberColumnFilter', type: 'numberColumn' },
    {
      headerName: 'Posting date',
      minWidth: 200,
      field: 'date',
      type: 'dateColumn',
      filter: 'agDateColumnFilter',
      valueFormatter: params => dateFormatter(params.data.date),
      filterParams: {
        filterOptions: [
          'equals',
          'notEqual',
          {
            displayKey: 'before',
            displayName: 'Before',
            predicate: ([filterValue], cellValue) => cellValue == null || cellValue < filterValue
          },
          {
            displayKey: 'after',
            displayName: 'After',
            predicate: ([filterValue], cellValue) => cellValue == null || cellValue > filterValue
          },
          {
            displayKey: 'betweenExclusive',
            displayName: 'Between (Exclusive)',
            predicate: ([fv1, fv2], cellValue) => cellValue == null || (fv1 < cellValue && fv2 > cellValue),
            numberOfInputs: 2
          },
          {
            displayKey: 'betweenInclusive',
            displayName: 'Between (Inclusive)',
            predicate: ([fv1, fv2], cellValue) => cellValue == null || (fv1 <= cellValue && fv2 >= cellValue),
            numberOfInputs: 2
          }
        ],
        comparator: (filterLocalDateAtMidnight, cellDate) => {
          if (cellDate > filterLocalDateAtMidnight) {
            return 1;
          } else if (cellDate < filterLocalDateAtMidnight) {
            return -1;
          }
          return 0;
        }
      }
    }
  ],
  rowData: rowData
};

const App = () => <MODatagrid options={gridOptions}></MODatagrid>;

Custom theme

You can use the theme attribute to further customize the style and spacing inside the grid.

<mo-datagrid id="theme-example"></mo-datagrid>

<script>
  const grid = document.querySelector('#theme-example');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);

  const gridOptions = {
    columnDefs: [
      {
        headerName: 'Make',
        field: 'make',
        sortable: true,
        filter: true
      },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
    ],
    rowData: rowData
  };

  const customTheme = {
    columnBorder: false,
    rowBorder: false,
    rowVerticalPaddingScale: 0.5,
    headerVerticalPaddingScale: 0.5,
    cellHorizontalPadding: 'var(--mo-spacing-x-small)',
    horizontalCellPadding: 'var(--mo-spacing-large)',
    oddRowBackgroundColor: "var(--mo-color-neutral-95)",
  };

  grid.options = gridOptions;
  grid.theme = customTheme;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000)
    });
  });
  return data;
};
const rowData = createMockData(30);

const gridOptions = {
  columnDefs: [
    {
      headerName: 'Make',
      field: 'make',
      sortable: true,
      filter: true
    },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
  ],
  rowData: rowData
};

const customTheme = {
  columnBorder: false,
  rowBorder: false,
  rowVerticalPaddingScale: 0.5,
  headerVerticalPaddingScale: 0.5,
  cellHorizontalPadding: 'var(--mo-spacing-x-small)',
  horizontalCellPadding: 'var(--mo-spacing-large)',
  oddRowBackgroundColor: "var(--mo-color-neutral-95)",
};

const App = () => <MODatagrid options={gridOptions} theme={customTheme}></MODatagrid>;

Loading state

You can use the loading property to show the loading message if you are still fetching your data. Setting it back to false will hide the message overlay.


Toggle loading state
<mo-datagrid loading id="loading-example"></mo-datagrid>
<br />
<mo-button id="loading-btn">Toggle loading state</mo-button>

<script>
  const grid = document.querySelector('#loading-example');
  const btn = document.querySelector('#loading-btn');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);

  const gridOptions = {
    columnDefs: [
      {
        headerName: 'Make',
        field: 'make',
        sortable: true,
        filter: true
      },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
    ],
    rowData: rowData
  };
  btn.addEventListener('click', () => {
    if (grid.loading) {
      grid.removeAttribute('loading');
    } else {
      grid.setAttribute('loading', true);
    }
  });
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000)
    });
  });
  return data;
};
const rowData = createMockData(30);

const gridOptions = {
  columnDefs: [
    {
      headerName: 'Make',
      field: 'make',
      sortable: true,
      filter: true
    },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
  ],
  rowData: rowData
};

// Implement property toggling logic here

const App = () => (
  <>
    <MODatagrid options={gridOptions}></MODatagrid>
    <br />
    <MOButton>Toggle loading state</MOButton>
  </>
);

Change detection

You can use the onCellValueChanged callback in the options api to detect changes made to cells and run your own logic accordingly. This simple example shows how to retrieve the previous and new value of the cell when changes occur. See the full return type here.



              

              
<mo-datagrid id="change-example"></mo-datagrid>
<pre id="changed-values"></pre>

<script>
  const grid = document.querySelector('#change-example');
  const pre = document.querySelector('#changed-values');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);
  const cellChanged = e => {
    pre.textContent = `Change detected!\nOld: ${e.oldValue}\nNew: ${e.value}`;
  };
  const gridOptions = {
    onCellValueChanged: cellChanged,
    defaultColDef: {
      editable: true,
      flex: 1
    },
    columnDefs: [
      {
        headerName: 'Make',
        field: 'make',
        sortable: true,
        filter: true
      },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
    ],
    rowData: rowData
  };
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000)
    });
  });
  return data;
};
const rowData = createMockData(30);

const cellChanged = e => {
  pre.textContent = `Change detected!\nOld: ${e.oldValue}\nNew: ${e.value}`;
};

const gridOptions = {
  onCellValueChanged: cellChanged,
  defaultColDef: {
    editable: true,
    flex: 1
  },
  columnDefs: [
    {
      headerName: 'Make',
      field: 'make',
      sortable: true,
      filter: true
    },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
  ],
  rowData: rowData
};

const App = () => <MODatagrid options={gridOptions}></MODatagrid>;

Row selection (with checkboxes)

By default hovering and selecting is limited to cells. However, row selection can be enabled with a few simple options.

Rows can be selected by:

  • clicking on a single row to select a single row
  • using the checkboxes or Command/Control + click to select multiple rows
  • Shift + click on two rows to select all rows between the two clicked rows
Export selected rows
<mo-datagrid id="row-selection"></mo-datagrid>
<div style="display: flex; justify-content: flex-end; gap: 8px; margin: 16px;">
  <mo-button id="row-selection-btn" variant="primary" style="margin-bottom: 8px;">Export selected rows</mo-button>
</div>
<mo-textarea
  label="Selected rows"
  readonly
  placeholder="Data from the selected rows will be here"
  id="selected-rows-area"
></mo-textarea>

<script>
  const grid = document.querySelector('#row-selection');
  const rowSelectionBtn = document.querySelector('#row-selection-btn');
  const textAreaRows = document.querySelector('#selected-rows-area');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);

  const gridOptions = {
    columnDefs: [
      {
        headerName: 'Make',
        field: 'make',
        sortable: true,
        filter: true,
      },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
    ],
    rowData: rowData,
    rowSelection: {
      headerCheckbox: true,
      checkboxes: true,
      mode: 'multiRow',
      enableClickSelection: true
    }
  };
  rowSelectionBtn.addEventListener('click', () => {
    const selectedRows = grid.grid.getSelectedRows();
    textAreaRows.value = JSON.stringify(selectedRows, null, ' ');
  });
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const [textValue, setTextValue] = useEffect('');

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000)
    });
  });
  return data;
};
const rowData = createMockData(30);

const gridOptions = {
  columnDefs: [
    {
      headerName: 'Make',
      field: 'make',
      sortable: true,
      filter: true,
      suppressRowClickSelection: true,
    },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Price', field: 'price', sortable: true, type: 'numberColumn' }
  ],
  rowSelection: {
    headerCheckbox: true,
    checkboxes: true,
    mode: 'multiRow',
    enableClickSelection: true
  },
  rowData: rowData
};

const getSelectedRows = () => {
  const selectedRows = grid.grid.getSelectedRows();
  setTextValue(JSON.stringify(selectedRows, null, ' '));
}

const App = () => (
  <>
    <MODatagrid options={gridOptions}></MODatagrid>
    <div style={{ display: "flex", justifyContent: "flex-end "gap: "8px", margin: "16px" }}>
      <MOButton variant="primary" style={{ marginBottom: "8px" }}>
        Export selected rows
      </MOButton>
    </div>
    <MOTextarea
      label="Selected rows"
      readonly
      placeholder="Data from the selected rows will be here"
      value={textValue}
    ></MOTextarea>
  </>
);

Compact and loose row height

The default row height is 40px, but users can choose to use either compact (32px) or loose (48px) rows.

Compact

Loose

<div style="display: flex; flex-direction: column; gap: 8px;">
  <h4 style="margin: 0">Compact</h4>
  <mo-datagrid compact id="compact"></mo-datagrid>
  <mo-divider></mo-divider>
  <h4 style="margin: 0">Loose</h4>
  <mo-datagrid loose id="loose"></mo-datagrid>
</div>

<script>
  const gridCompact = document.querySelector('#compact');
  const gridLoose = document.querySelector('#loose');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);
  const gridOptions = {
    defaultColDef: {
      editable: true,
      resizable: true,
      minWidth: 100,
      flex: 1
    },
    columnDefs: [
      { headerName: 'Make', field: 'make' },
      { headerName: 'Model', field: 'model' },
      { headerName: 'Price', field: 'price', type: 'numberColumn' }
    ],
    rowData: rowData
  };
  // copy options to create new reference
  const gridOptionsLoose = {
    ...gridOptions
  };
  gridCompact.options = gridOptions;
  gridLoose.options = gridOptionsLoose;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000)
    });
  });
  return data;
};
const rowData = createMockData(30);
const gridOptions = {
  defaultColDef: {
    editable: true,
    resizable: true,
    minWidth: 100,
    flex: 1
  },
  columnDefs: [
    { headerName: 'Make', field: 'make' },
    { headerName: 'Model', field: 'model' },
    { headerName: 'Price', field: 'price', type: 'numberColumn' }
  ],
  rowData: rowData
};
// copy options to create new reference
const gridOptionsLoose = {
  ...gridOptions
};

const App = () => (
  <>
    <MODatagrid compact options={gridOptions}></MODatagrid>
    <MODatagrid loose options={gridOptionsLoose}></MODatagrid>
  </>
);

Pinned/sticky columns

It is possible to pin certain columns to allow users to keep track of key column values when scrolling through a long list of columns.

<mo-datagrid id="pinned"></mo-datagrid>

<script>
  const grid = document.querySelector('#pinned');

  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.max(Math.ceil(Math.random() * 100000), 5000),
        year: Math.ceil(2000 + Math.random() * 22),
        odometer: Math.max(Math.ceil(Math.random() * 160000), 10000),
        fuel: Math.random() > 0.5 ? 'Diesel' : 'Gasoline',
        condition: Math.random() > 0.5 ? 'Good' : 'Bad'
      });
    });
    return data;
  }
  const rowData = createMockData(50);
  const gridOptions = {
    defaultColDef: {
      flex: 0
    },
    columnDefs: [
      { headerName: 'Make', field: 'make', sortable: true, filter: true, pinned: 'left' },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Year', field: 'year', sortable: true, type: 'numberColumn' },
      { headerName: 'Fuel', field: 'fuel' },
      { headerName: 'Condition', field: 'condition' },
      {
        headerName: 'Odometer',
        field: 'odometer',
        sortable: true,
        type: 'numberColumn'
      },
      {
        headerName: 'Price',
        field: 'price',
        sortable: true,
        editable: true,
        type: 'numberColumn'
      }
    ],
    rowData: rowData
  };
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.max(Math.ceil(Math.random() * 100000), 5000),
      year: Math.ceil(2000 + Math.random() * 22),
      odometer: Math.max(Math.ceil(Math.random() * 160000), 10000),
      fuel: Math.random() > 0.5 ? 'Diesel' : 'Gasoline',
      condition: Math.random() > 0.5 ? 'Good' : 'Bad'
    });
  });
  return data;
};
const rowData = createMockData(50);
const gridOptions = {
  defaultColDef: {
    flex: 0
  },
  columnDefs: [
    { headerName: 'Make', field: 'make', sortable: true, filter: true, pinned: 'left' },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Year', field: 'year', sortable: true, type: 'numberColumn' },
    { headerName: 'Fuel', field: 'fuel' },
    { headerName: 'Condition', field: 'condition' },
    {
      headerName: 'Odometer',
      field: 'odometer',
      sortable: true,
      type: 'numberColumn'
    },
    {
      headerName: 'Price',
      field: 'price',
      sortable: true,
      editable: true,
      type: 'numberColumn'
    }
  ],
  rowData: rowData
};

const App = () => <MODatagrid options={gridOptions}></MODatagrid>;

Pagination

Pagination can be enabled by simply setting it to true in the options object. The price column in this example is editable and its numerical values have been formatted using the valueFormatter column definition. See source code for examples.

<mo-datagrid id="grid-pagination"></mo-datagrid>

<script>
  const grid = document.querySelector('#grid-pagination');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.ceil(5000 + Math.random() * 100000),
        year: Math.ceil(2000 + Math.random() * 22),
        odometer: Math.ceil(10000 + Math.random() * 160000)
      });
    });
    return data;
  }
  const rowData = createMockData(36540);
  function currencyFormatter(price, sign) {
    var sansDec = parseInt(price).toFixed(0);
    var formatted = sansDec.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return sign + `${formatted}`;
  }
  function distanceFormatter(price, unit) {
    var sansDec = parseInt(price).toFixed(0);
    var formatted = sansDec.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return `${formatted}` + unit;
  }
  const gridOptions = {
    columnDefs: [
      { headerName: 'Make', field: 'make', sortable: true, filter: true },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Year', field: 'year', sortable: true, type: 'numberColumn' },
      {
        headerName: 'Odometer',
        field: 'odometer',
        sortable: true,
        type: 'numberColumn',
        valueFormatter: params => distanceFormatter(params.data.odometer, ' km')
      },
      {
        headerName: 'Price',
        field: 'price',
        sortable: true,
        editable: true,
        type: 'numberColumn',
        valueFormatter: params => currencyFormatter(params.data.price, '$')
      }
    ],
    rowData: rowData,
    pagination: true
  };
  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.ceil(5000 + Math.random() * 100000),
      year: Math.ceil(2000 + Math.random() * 22),
      odometer: Math.ceil(10000 + Math.random() * 160000)
    });
  });
  return data;
};
const rowData = createMockData(36540);
const currencyFormatter = (price, sign) => {
  var sansDec = parseInt(price).toFixed(0);
  var formatted = sansDec.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  return sign + `${formatted}`;
};
const distanceFormatter = (price, unit) => {
  var sansDec = parseInt(price).toFixed(0);
  var formatted = sansDec.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  return `${formatted}` + unit;
};
const gridOptions = {
  columnDefs: [
    { headerName: 'Make', field: 'make', sortable: true, filter: true },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Year', field: 'year', sortable: true, type: 'numberColumn' },
    {
      headerName: 'Odometer',
      field: 'odometer',
      sortable: true,
      type: 'numberColumn',
      valueFormatter: params => distanceFormatter(params.data.odometer, ' km')
    },
    {
      headerName: 'Price',
      field: 'price',
      sortable: true,
      editable: true,
      type: 'numberColumn',
      valueFormatter: params => currencyFormatter(params.data.price, '$')
    }
  ],
  rowData: rowData,
  pagination: true
};

const App = () => <MODatagrid options={gridOptions}></MODatagrid>;

Export data as .csv file

Data from the data grid can be exported in to a .csv format, and downloaded. These can be achieved by using the grid.grid functions getDataAsCsv and exportDataAsCsv.

Export data to text field Download exported csv data
<mo-datagrid id="csv"></mo-datagrid>
<div style="display: flex; justify-content: flex-end; gap: 8px; margin: 16px;">
  <mo-button id="textarea-btn" variant="secondary" style="margin-bottom: 8px;">Export data to text field</mo-button>
  <mo-button id="export-btn" style="margin-bottom: 8px;">Download exported csv data</mo-button>
</div>
<mo-textarea label="CSV output" readonly placeholder="CSV data will be here" id="csv-output"></mo-textarea>

<script>
  const moGrid = document.querySelector('#csv');
  const textarea = document.querySelector('#csv-output');
  const exportBtn = document.querySelector('#export-btn');
  const textareaBtn = document.querySelector('#textarea-btn');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.ceil(5000 + Math.random() * 100000)
      });
    });
    return data;
  }
  const rowData = createMockData(30);
  const gridOptions = {
    defaultColDef: {
      editable: true,
      resizable: true,
      minWidth: 100,
      flex: 1
    },
    columnDefs: [
      { headerName: 'Make', field: 'make' },
      { headerName: 'Model', field: 'model' },
      { headerName: 'Price', field: 'price', type: 'numberColumn' }
    ],
    rowData: rowData
  };
  textareaBtn.addEventListener('click', () => {
    textarea.value = moGrid.grid.getDataAsCsv();
  });
  exportBtn.addEventListener('click', () => {
    moGrid.grid.exportDataAsCsv();
  });
  moGrid.options = gridOptions;
</script>
import { MODatagrid, MOButton, MOTextarea } from '@metsooutotec/modes-web-components/dist/react';

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.ceil(5000 + Math.random() * 100000)
    });
  });
  return data;
};
const rowData = createMockData(30);
const gridOptions = {
  defaultColDef: {
    editable: true,
    resizable: true,
    minWidth: 100,
    flex: 1
  },
  columnDefs: [
    { headerName: 'Make', field: 'make' },
    { headerName: 'Model', field: 'model' },
    { headerName: 'Price', field: 'price', type: 'numberColumn' }
  ],
  rowData: rowData
};
const getData = () => {
  textarea.value = grid.grid.getDataAsCsv();
};
const exportData = () => {
  grid.grid.exportDataAsCsv();
};

const App = () => (
  <>
    <MODatagrid options={gridOptions}></MODatagrid>
    <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '8px', margin: '16px' }}>
      <MOButton onClick={getData} variant="secondary" style={{ marginBottom: '8px' }}>
        Export data to text field
      </MOButton>
      <MOButton onClick={exportData} style={{ marginBottom: '8px' }}>
        Download exported csv data
      </MOButton>
    </div>
    <MOTextarea label="CSV output" readonly placeholder="CSV data will be here"></MOTextarea>
  </>
);

Dragging and dropping cells

The data grid supports dragging and dropping of cells. Drag and drop can be enabled by setting the value of dndSource to true in the column definitions. This example shows how the grid can be combined with a mo-drop-handler to extract data out of the cell/row.

Drop cells here
<div class="container">
  <mo-datagrid height="100%" id="reordering"></mo-datagrid>
  <mo-icon class="arrow-icon" name="arrow-down"></mo-icon>
  <mo-drop-handler id="drop-handler">
    <div id="message" class="drop-handler-content">Drop cells here</div>
  </mo-drop-handler>
  <mo-textarea
    placeholder="Dropped items will be shown here"
    label="Dropped items"
    readonly
    id="dropped-items"
  ></mo-textarea>
</div>

<script>
  const grid = document.querySelector('#reordering');
  const dropHandler = document.querySelector('#drop-handler');
  const message = document.querySelector('#message');
  const textarea = document.querySelector('#dropped-items');
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.ceil(5000 + Math.random() * 100000)
      });
    });
    return data;
  }
  const rowData = createMockData(500);
  dropHandler.addEventListener('mo-drop', event => {
    const cellJson = event.detail.event.dataTransfer.getData('application/json');
    const currentValue = textarea.value;
    const newValue = currentValue.concat(`${currentValue.length !== 0 ? ',\n' : ''}` + cellJson);
    textarea.value = newValue;
  });
  const gridOptions = {
    defaultColDef: {
      editable: true,
      resizable: true,
      minWidth: 100,
      flex: 1
    },
    columnDefs: [
      { headerName: 'Make', field: 'make', dndSource: true },
      { headerName: 'Model', field: 'model' },
      { headerName: 'Price', field: 'price', type: 'numberColumn' }
    ],
    rowData: rowData,
    rowDragManaged: true,
    animateRows: true
  };
  grid.options = gridOptions;
</script>
<style>
  .container {
    display: flex;
    gap: 16px;
    height: 800px;
    flex-direction: column;
  }
  .arrow-icon {
    font-size: 48px;
    margin-left: calc(16.5% - 24px);
  }
  .drop-handler-content {
    padding: 1rem 1.5rem;
    border: 1px dashed var(--mo-color-secondary-70);
    transition: all var(--mo-transition-medium) ease-in-out;
  }
  mo-drop-handler[dragged] .drop-handler {
    border-color: var(--mo-color-secondary-30);
    background-color: var(--mo-color-secondary-90);
  }
</style>
import { MODatagrid, MODropHandler, MOIcon, MOTextarea } from '@metsooutotec/modes-web-components/dist/react';

const css = `
  .container {
    display: flex;
    gap: 16px;
    flex-direction: column;
  }
  .arrow-icon {
    font-size: 48px;
    margin-left: calc(16.5% - 24px);
  }
  .drop-handler-content {
    padding: 1rem 1.5rem;
    border: 1px dashed var(--mo-color-secondary-70);
    transition: all var(--mo-transition-medium) ease-in-out;
  }
  mo-drop-handler[dragged] .drop-handler {
    border-color: var(--mo-color-secondary-30);
    background-color: var(--mo-color-secondary-90);
  }
`;

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.ceil(5000 + Math.random() * 100000)
    });
  });
  return data;
};
const rowData = createMockData(500);
const onDrop = event => {
  const cellJson = event.detail.dataTransfer.getData('application/json');
  const currentValue = textarea.value;
  const newValue = currentValue.concat(`${currentValue.length !== 0 ? ',\n' : ''}` + cellJson);
  textarea.value = newValue;
};

const gridOptions = {
  defaultColDef: {
    editable: true,
    resizable: true,
    minWidth: 100,
    flex: 1
  },
  columnDefs: [
    { headerName: 'Make', field: 'make', dndSource: true },
    { headerName: 'Model', field: 'model' },
    { headerName: 'Price', field: 'price', type: 'numberColumn' }
  ],
  rowData: rowData,
  rowDragManaged: true,
  animateRows: true
};

const App = () => (
  <>
    <div class="container">
      <MODatagrid height="100%"></MODatagrid>
      <MOIcon class="arrow-icon" name="arrow-down"></MOIcon>
      <MODropHandler onMoDrop={event => onDrop(event)}>
        <div class="drop-handler-content">Drop cells here</div>
      </MODropHandler>
      <MOTextarea placeholder="Dropped items will be shown here" label="Dropped items" readonly></MOTextarea>
    </div>
    <style>{css}</style>
  </>
);

Changing column order and saving the state

As mentioned above, unfortunately dragging and dropping columns to re-order them is not functional in this version of ag-grid. However, column order can still be changed programmatically, and the state of the column order and sorting can be saved, reset or restored.

Column control

Price first Model last Sort by Odometer

State control

<mo-datagrid id="save-state"></mo-datagrid>
<mo-divider style="margin: 2em 0;"></mo-divider>
<div style="display: flex; justify-content: space-between;">
  <div>
    <p style="margin: 0; font-family: GT-Eesti">Column control</p>
    <mo-button-group>
      <mo-button id="price-first">Price first</mo-button>
      <mo-button id="make-last">Model last</mo-button>
      <mo-button id="sort-odometer">Sort by Odometer</mo-button>
    </mo-button-group>
  </div>
  <div>
    <p style="margin: 0; text-align: end; font-family: GT-Eesti">State control</p>
    <mo-button-group>
      <mo-tooltip id="save-tooltip" content="Save">
        <mo-button id="save-btn"><mo-icon name="save"></mo-icon></mo-button>
      </mo-tooltip>
      <mo-tooltip content="Restore">
        <mo-button id="restore-btn"><mo-icon name="reload"></mo-icon></mo-button>
      </mo-tooltip>
      <mo-tooltip content="Reset">
        <mo-button id="reset-btn"><mo-icon name="refresh"></mo-icon></mo-button>
      </mo-tooltip>
    </mo-button-group>
  </div>
</div>

<script>
  const moGrid = document.querySelector('#save-state');
  const priceFirst = document.querySelector('#price-first');
  const modelLast = document.querySelector('#make-last');
  const sortOdometer = document.querySelector('#sort-odometer');
  const saveBtn = document.querySelector('#save-btn');
  const restoreBtn = document.querySelector('#restore-btn');
  const resetBtn = document.querySelector('#reset-btn');
  const saveTooltip = document.querySelector('#save-tooltip');

  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.ceil(5000 + Math.random() * 100000),
        year: Math.ceil(2000 + Math.random() * 22),
        odometer: Math.ceil(10000 + Math.random() * 160000)
      });
    });
    return data;
  }
  const rowData = createMockData(150);
  const gridOptions = {
    defaultColDef: {
      resizable: true,
      minWidth: 100,
      flex: 1
    },
    columnDefs: [
      { headerName: 'Make', field: 'make', sortable: true, filter: true },
      { headerName: 'Model', field: 'model', sortable: true },
      { headerName: 'Year', field: 'year', sortable: true, type: 'numberColumn' },
      {
        headerName: 'Odometer',
        field: 'odometer',
        sortable: true,
        type: 'numberColumn'
      },
      {
        headerName: 'Price',
        field: 'price',
        sortable: true,
        editable: true,
        type: 'numberColumn'
      }
    ],
    rowData: rowData
  };

  priceFirst.addEventListener('click', () => {
    moGrid.grid.moveColumn('price', 0);
    // redraw rows to make cell borders render correctly
    moGrid.grid.redrawRows();
  });
  modelLast.addEventListener('click', () => {
    moGrid.grid.moveColumn('model', 4);
    // redraw rows to make cell borders render correctly
    moGrid.grid.redrawRows();
  });
  sortOdometer.addEventListener('click', () => {
    moGrid.grid.applyColumnState({
      state: [{ colId: 'odometer', sort: 'asc' }],
      defaultState: { sort: null }
    });
  });
  saveBtn.addEventListener('click', () => {
    localStorage.setItem('colState', JSON.stringify(moGrid.grid.getColumnState()));
    saveTooltip.content = 'State saved succesfully.';
    setTimeout(() => {
      saveTooltip.content = 'Save';
    }, 2000);
  });
  restoreBtn.addEventListener('click', () => {
    if (localStorage.getItem('colState')) {
      moGrid.grid.applyColumnState({
        state: JSON.parse(localStorage.getItem('colState')),
        applyOrder: true
      });
    }
  });
  resetBtn.addEventListener('click', () => {
    moGrid.grid.resetColumnState();
  });
  moGrid.options = gridOptions;
</script>
import {
  MODatagrid,
  MOButtonGroup,
  MOButton,
  MOIcon,
  MOTooltip,
  MODivider
} from '@metsooutotec/modes-web-components/dist/react';

const [saveContent, setSaveContent] = useState('Save');

const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.ceil(5000 + Math.random() * 100000),
      year: Math.ceil(2000 + Math.random() * 22),
      odometer: Math.ceil(10000 + Math.random() * 160000)
    });
  });
  return data;
};
const rowData = createMockData(150);
const gridOptions = {
  defaultColDef: {
    resizable: true,
    minWidth: 100,
    flex: 1
  },
  columnDefs: [
    { headerName: 'Make', field: 'make', sortable: true, filter: true },
    { headerName: 'Model', field: 'model', sortable: true },
    { headerName: 'Year', field: 'year', sortable: true, type: 'numberColumn' },
    {
      headerName: 'Odometer',
      field: 'odometer',
      sortable: true,
      type: 'numberColumn'
    },
    {
      headerName: 'Price',
      field: 'price',
      sortable: true,
      editable: true,
      type: 'numberColumn'
    }
  ],
  rowData: rowData
};

const priceFirst = () => {
  grid.grid.moveColumn('price', 0);
  // redraw rows to make cell borders render correctly
  grid.grid.redrawRows();
};

const modelLast = () => {
  grid.grid.moveColumn('model', 4);
  // redraw rows to make cell borders render correctly
  grid.grid.redrawRows();
};

const sortOdometer = () => {
  grid.grid.applyColumnState({
    state: [{ colId: 'odometer', sort: 'asc' }],
    defaultState: { sort: null }
  });
};

const saveState = () => {
  localStorage.setItem('colState', JSON.stringify(grid.grid.getColumnState()));
  setSaveContent('State saved succesfully.');
  setTimeout(() => {
    setSaveContent('Save');
  }, 2000);
};

const restoreState = () => {
  if (localStorage.getItem('colState')) {
    grid.grid.applyColumnState({
      state: JSON.parse(localStorage.getItem('colState')),
      applyOrder: true
    });
  }
};

const resetState = () => {
  grid.grid.resetColumnState();
};

const App = () => (
  <>
    <MODatagrid options={gridOptions}></MODatagrid>
    <MODivider style={{ margin: '2em 0' }}></MODivider>
    <div style={{ display: 'flex', justifyContent: 'space-between' }}>
      <div>
        <p style={{ margin: 0, fontFamily: 'GT-Eesti' }}>Column control</p>
        <MOButtonGroup>
          <MOButton onClick={priceFirst()}>Price first</MOButton>
          <MOButton onClick={modelLast()}>Model last</MOButton>
          <MOButton onClick={sortOdometer()}>Sort by Odometer</MOButton>
        </MOButtonGroup>
      </div>
      <div>
        <p style={{ margin: 0, textAlign: 'end', fontFamily: 'GT-Eesti' }}>State control</p>
        <MOButtonGroup>
          <MOTooltip content={saveContent}>
            <MOButton>
              <MOIcon onClick={saveState()} name="save"></MOIcon>
            </MOButton>
          </MOTooltip>
          <MOTooltip content="Restore">
            <MOButton onClick={restoreState()}>
              <MOIcon name="reload"></MOIcon>
            </MOButton>
          </MOTooltip>
          <MOTooltip content="Reset">
            <MOButton onClick={resetState()}>
              <MOIcon name="refresh"></MOIcon>
            </MOButton>
          </MOTooltip>
        </MOButtonGroup>
      </div>
    </div>
  </>
);

Localization

All the displayed text in the grid is customisable for the purposes of localisation. This is done by providing locale information to the grid for the required language. Either provide an object of key/value pairs via the localeText property, or provide a getLocaleText callback to hook the grid up to your application’s localisation.

English Suomi

<div style="display: flex; justify-content: flex-end">
  <mo-select id="locale-select" style="width: 125px" label="Choose locale" value="fin">
    <mo-option value="en">English</mo-option>
    <mo-option value="fin">Suomi</mo-option>
  </mo-select>
</div>
<br />
<mo-datagrid id="grid-localization"></mo-datagrid>

<script>
  const grid = document.querySelector('#grid-localization');
  const select = document.querySelector('#locale-select');
  let locale = 'fin';
  const localeTextEN = {
    // custom specific
    make: 'Make',
    model: 'Model',
    price: 'Price',

    // Set Filter
    selectAll: '(Select All)',
    selectAllSearchResults: '(Select All Search Results)',
    searchOoo: 'Search...',
    blanks: '(Blanks)',
    noMatches: 'No matches',

    // Number Filter & Text Filter
    filterOoo: 'Filter...',
    equals: 'Equals',
    notEqual: 'Not equal',
    blank: 'Blank',
    notBlank: 'Not blank',
    empty: 'Choose One',

    // Number Filter
    lessThan: 'Less than',
    greaterThan: 'Greater than',
    lessThanOrEqual: 'Less than or equal',
    greaterThanOrEqual: 'Greater than or equal',
    inRange: 'In range',
    inRangeStart: 'from',
    inRangeEnd: 'to',

    // Text Filter
    contains: 'Contains',
    notContains: 'Not contains',
    startsWith: 'Starts with',
    endsWith: 'Ends with',

    // Date Filter
    dateFormatOoo: 'yyyy-mm-dd',

    // Filter Conditions
    andCondition: 'AND',
    orCondition: 'OR',

    // Filter Buttons
    applyFilter: 'Apply',
    resetFilter: 'Reset',
    clearFilter: 'Clear',
    cancelFilter: 'Cancel',

    // Filter Titles
    textFilter: 'Text Filter',
    numberFilter: 'Number Filter',
    dateFilter: 'Date Filter',
    setFilter: 'Set Filter',

    // Side Bar
    columns: 'Columns',
    filters: 'Filters',

    // columns tool panel
    pivotMode: 'Pivot Mode',
    groups: 'Row Groups',
    rowGroupColumnsEmptyMessage: 'Drag here to set row groups',
    values: 'Values',
    valueColumnsEmptyMessage: 'Drag here to aggregate',
    pivots: 'Column Labels',
    pivotColumnsEmptyMessage: 'Drag here to set column labels',

    // Header of the Default Group Column
    group: 'Group',

    // Row Drag
    rowDragRows: 'rows',

    // Other
    loadingOoo: 'Loading...',
    noRowsToShow: 'No Rows To Show',
    enabled: 'Enabled'
  };
  const localeTextFI = {
    // custom specific
    make: 'Valmistaja',
    model: 'Malli',
    price: 'Hinta',

    // Set Filter
    selectAll: '(Valitse kaikki)',
    selectAllSearchResults: '(Valitse kaikki haun tulokset)',
    searchOoo: 'Hae...',
    blanks: '(Tyhjää)',
    noMatches: 'Ei osumia',

    // Number Filter & Text Filter
    filterOoo: 'Suodata...',
    equals: 'Yhtäsuuri kuin',
    notEqual: 'Erisuuri kuin',
    blank: 'Tyhjä',
    notBlank: 'Ei tyhjä',
    empty: 'Valitse yksi',

    // Number Filter
    lessThan: 'Vähemmän kuin',
    greaterThan: 'Suurempi kuin',
    lessThanOrEqual: 'Vähemmän tai yhtäsuuri kuin',
    greaterThanOrEqual: 'Suurempi tai yhtäsuuri kuin',
    inRange: 'Välillä',
    inRangeStart: 'alku',
    inRangeEnd: 'loppu',

    // Text Filter
    contains: 'Sisältää',
    notContains: 'Ei sisällä',
    startsWith: 'Alkaa',
    endsWith: 'Loppuu',

    // Date Filter
    dateFormatOoo: 'dd-mm-yyyy',

    // Filter Conditions
    andCondition: 'JA',
    orCondition: 'TAI',

    // Filter Buttons
    applyFilter: 'Käytä',
    resetFilter: 'Nollaa',
    clearFilter: 'Tyhjennä',
    cancelFilter: 'Peruuta',

    // Filter Titles
    textFilter: 'Teksti suodatin',
    numberFilter: 'Numero suodatin',
    dateFilter: 'Päivämäärä suodatin',
    setFilter: 'Aseta suodatin',

    // Side Bar
    columns: 'Kolumnit',
    filters: 'Suodattimet',

    // Header of the Default Group Column
    group: 'Ryhmä',

    // Row Drag
    rowDragRows: 'rivit',

    // Other
    loadingOoo: 'Lataa...',
    noRowsToShow: 'Ei näytetäviä rivejä',
    enabled: 'Käytössä'
  };
  function createMockData(rows) {
    const data = [];
    const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
    const models = ['Superb', 'Celica', 'A4', 'Civic'];
    Array.from(Array(rows)).forEach((x, i) => {
      data.push({
        make: makes[Math.ceil(Math.random() * makes.length) - 1],
        model: models[Math.ceil(Math.random() * models.length) - 1],
        price: Math.ceil(5000 + Math.random() * 100000)
      });
    });
    return data;
  }
  const rowData = createMockData(50);
  function getLocaleText() {
    return locale === 'en' ? localeTextEN : localeTextFI;
  }
  const gridOptions = {
    localeText: getLocaleText(),
    columnDefs: [
      { headerName: getLocaleText().make, field: 'make', sortable: true, filter: true },
      { headerName: getLocaleText().model, field: 'model', sortable: true },
      { headerName: getLocaleText().price, field: 'price', sortable: true, type: 'numberColumn' }
    ],
    rowData: rowData
  };
  select.addEventListener('mo-change', event => {
    locale = event.target.value;
    grid.options = {
      localeText: getLocaleText(),
      columnDefs: [
        { headerName: getLocaleText().make, field: 'make', sortable: true, filter: true },
        { headerName: getLocaleText().model, field: 'model', sortable: true },
        { headerName: getLocaleText().price, field: 'price', sortable: true, type: 'numberColumn' }
      ],
      rowData: rowData
    };
    // re-draw grid to update locale
    grid.refreshGrid();
  });

  grid.options = gridOptions;
</script>
import { MODatagrid } from '@metsooutotec/modes-web-components/dist/react';

var locale = 'fin';
const localeTextEN = {
  // custom specific
  make: 'Make',
  model: 'Model',
  price: 'Price',

  // Set Filter
  selectAll: '(Select All)',
  selectAllSearchResults: '(Select All Search Results)',
  searchOoo: 'Search...',
  blanks: '(Blanks)',
  noMatches: 'No matches',

  // Number Filter & Text Filter
  filterOoo: 'Filter...',
  equals: 'Equals',
  notEqual: 'Not equal',
  blank: 'Blank',
  notBlank: 'Not blank',
  empty: 'Choose One',

  // Number Filter
  lessThan: 'Less than',
  greaterThan: 'Greater than',
  lessThanOrEqual: 'Less than or equal',
  greaterThanOrEqual: 'Greater than or equal',
  inRange: 'In range',
  inRangeStart: 'from',
  inRangeEnd: 'to',

  // Text Filter
  contains: 'Contains',
  notContains: 'Not contains',
  startsWith: 'Starts with',
  endsWith: 'Ends with',

  // Date Filter
  dateFormatOoo: 'yyyy-mm-dd',

  // Filter Conditions
  andCondition: 'AND',
  orCondition: 'OR',

  // Filter Buttons
  applyFilter: 'Apply',
  resetFilter: 'Reset',
  clearFilter: 'Clear',
  cancelFilter: 'Cancel',

  // Filter Titles
  textFilter: 'Text Filter',
  numberFilter: 'Number Filter',
  dateFilter: 'Date Filter',
  setFilter: 'Set Filter',

  // Side Bar
  columns: 'Columns',
  filters: 'Filters',

  // columns tool panel
  pivotMode: 'Pivot Mode',
  groups: 'Row Groups',
  rowGroupColumnsEmptyMessage: 'Drag here to set row groups',
  values: 'Values',
  valueColumnsEmptyMessage: 'Drag here to aggregate',
  pivots: 'Column Labels',
  pivotColumnsEmptyMessage: 'Drag here to set column labels',

  // Header of the Default Group Column
  group: 'Group',

  // Row Drag
  rowDragRows: 'rows',

  // Other
  loadingOoo: 'Loading...',
  noRowsToShow: 'No Rows To Show',
  enabled: 'Enabled'
};
const localeTextFI = {
  // custom specific
  make: 'Valmistaja',
  model: 'Malli',
  price: 'Hinta',

  // Set Filter
  selectAll: '(Valitse kaikki)',
  selectAllSearchResults: '(Valitse kaikki haun tulokset)',
  searchOoo: 'Hae...',
  blanks: '(Tyhjää)',
  noMatches: 'Ei osumia',

  // Number Filter & Text Filter
  filterOoo: 'Suodata...',
  equals: 'Yhtäsuuri kuin',
  notEqual: 'Erisuuri kuin',
  blank: 'Tyhjä',
  notBlank: 'Ei tyhjä',
  empty: 'Valitse yksi',

  // Number Filter
  lessThan: 'Vähemmän kuin',
  greaterThan: 'Suurempi kuin',
  lessThanOrEqual: 'Vähemmän tai yhtäsuuri kuin',
  greaterThanOrEqual: 'Suurempi tai yhtäsuuri kuin',
  inRange: 'Välillä',
  inRangeStart: 'alku',
  inRangeEnd: 'loppu',

  // Text Filter
  contains: 'Sisältää',
  notContains: 'Ei sisällä',
  startsWith: 'Alkaa',
  endsWith: 'Loppuu',

  // Date Filter
  dateFormatOoo: 'dd-mm-yyyy',

  // Filter Conditions
  andCondition: 'JA',
  orCondition: 'TAI',

  // Filter Buttons
  applyFilter: 'Käytä',
  resetFilter: 'Nollaa',
  clearFilter: 'Tyhjennä',
  cancelFilter: 'Peruuta',

  // Filter Titles
  textFilter: 'Teksti suodatin',
  numberFilter: 'Numero suodatin',
  dateFilter: 'Päivämäärä suodatin',
  setFilter: 'Aseta suodatin',

  // Side Bar
  columns: 'Kolumnit',
  filters: 'Suodattimet',

  // Header of the Default Group Column
  group: 'Ryhmä',

  // Row Drag
  rowDragRows: 'rivit',

  // Other
  loadingOoo: 'Lataa...',
  noRowsToShow: 'Ei näytetäviä rivejä',
  enabled: 'Käytössä'
};
const createMockData = rows => {
  const data = [];
  const makes = ['Toyota', 'Honda', 'Skoda', 'Audi'];
  const models = ['Superb', 'Celica', 'A4', 'Civic'];
  Array.from(Array(rows)).forEach((x, i) => {
    data.push({
      make: makes[Math.ceil(Math.random() * makes.length) - 1],
      model: models[Math.ceil(Math.random() * models.length) - 1],
      price: Math.ceil(5000 + Math.random() * 100000)
    });
  });
  return data;
};
const rowData = createMockData(50);
const getLocaleText = () => {
  return locale === 'en' ? localeTextEN : localeTextFI;
};
const gridOptions = {
  localeText: getLocaleText(),
  columnDefs: [
    { headerName: getLocaleText().make, field: 'make', sortable: true, filter: true },
    { headerName: getLocaleText().model, field: 'model', sortable: true },
    { headerName: getLocaleText().price, field: 'price', sortable: true, type: 'numberColumn' }
  ],
  rowData: rowData
};

const updateLocale = event => {
  locale = event.target.value;
  grid.options = {
    localeText: getLocaleText(),
    columnDefs: [
      { headerName: getLocaleText().make, field: 'make', sortable: true, filter: true },
      { headerName: getLocaleText().model, field: 'model', sortable: true },
      { headerName: getLocaleText().price, field: 'price', sortable: true, type: 'numberColumn' }
    ],
    rowData: rowData
  };
  // re-draw grid to update locale
  grid.refreshGrid();
};

const App = () => (
  <>
    <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
      <MOSelect onMoSelect={event => updateLocale(event)} style={{ width: '125px' }} label="Choose locale" value="fin">
        <MOOption value="en">English</MOOption>
        <MOOption value="fin">Suomi</MOOption>
      </MOSelect>
    </div>
    <MODatagrid options={gridOptions}></MODatagrid>
  </>
);

Importing

If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.

Bundler React Script

To import this component using a bundler:

import '@metsooutotec/modes-web-components/dist/components/datagrid/datagrid.js';

To import this component as a React component:

import MODatagrid from '@metsooutotec/modes-web-components/dist/react/datagrid/';

To import this component using a script tag:

<script type="module" src="https://modes-web.metso.com/dist/components/cdn/components/datagrid/datagrid.js"></script>

Properties

Name Description Reflects Type Default
grid Reference to the grid itself. It would make more sense to call this api after ag-grid v31 but to avoid breaking changes it is still called grid GridApi -
options Options to supply to the Grid. GridOptions -
height Static height of the grid. string '350px'
compact Makes the grid more compact by changing row height to 32px. boolean false
loose Makes the grid looser by changing row height to 48px. boolean false
loading Set this to true to showcase a loading message while fetching data. Toggle off to remove message. boolean false
theme Custom theme for the grid CustomizableThemeParams | undefined -
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Dependencies

This component automatically imports the following dependencies.