Skip to main content
Default Gray Amethyst

Table

<mo-table> | MOTable
Since 2.0 stable

Tables are used to display data in a tabular format.

Table is a lightweight and un-opinionated component for enhancing tabular data. It offer built-in styles, row selection, sorting, and virtualization. For a more feature-rich and heavier table, use the data grid component.

User Age Email Bryan 25 bryan@email.com George 40 georgie@email.com Louise 32 louise@email.com Augustina 52 augustina@email.com Donna 39 donna@email.com
<mo-table>
  <mo-table-head>
    <mo-table-head-cell>User</mo-table-head-cell>
    <mo-table-head-cell>Age</mo-table-head-cell>
    <mo-table-head-cell>Email</mo-table-head-cell>
  </mo-table-head>
  <mo-table-body>
    <mo-table-row>
      <mo-table-cell>Bryan</mo-table-cell>
      <mo-table-cell>25</mo-table-cell>
      <mo-table-cell>bryan@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>George</mo-table-cell>
      <mo-table-cell>40</mo-table-cell>
      <mo-table-cell>georgie@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Louise</mo-table-cell>
      <mo-table-cell>32</mo-table-cell>
      <mo-table-cell>louise@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Augustina</mo-table-cell>
      <mo-table-cell>52</mo-table-cell>
      <mo-table-cell>augustina@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Donna</mo-table-cell>
      <mo-table-cell>39</mo-table-cell>
      <mo-table-cell>donna@email.com</mo-table-cell>
    </mo-table-row>
  </mo-table-body>
</mo-table>
import { MOTable } from '@metsooutotec/modes-web-components/dist/react';

const App = () => (
  <MOTable>
    <MOTableHead>
      <MOTableHeadCell>User</MOTableHeadCell>
      <MOTableHeadCell>Age</MOTableHeadCell>
      <MOTableHeadCell>Email</MOTableHeadCell>
    </MOTableHead>
    <MOTableBody>
      <MOTableRow>
        <MOTableCell>Bryan</MOTableCell>
        <MOTableCell>25</MOTableCell>
        <MOTableCell>bryan@email.com</MOTableCell>
      </MOTableRow>
      {...}
    </MOTableBody>
  </MOTable>
);

Style customization

As the mo-table is composed of sub-components (e.g., mo-table-row), you should apply the styling to the respective sub-components as needed. The code below shows some examples on how to achieve this.

Custom colors

You can highlight rows or cell by targeting them with simple css rules.

User Age Email Bryan 25 bryan@email.com George 40 georgie@email.com Louise 32 louise@email.com Augustina 52 augustina@email.com Donna 39 donna@email.com
<mo-table class="styled-table">
  <mo-table-head>
    <mo-table-head-cell>User</mo-table-head-cell>
    <mo-table-head-cell>Age</mo-table-head-cell>
    <mo-table-head-cell>Email</mo-table-head-cell>
  </mo-table-head>
  <mo-table-body>
    <mo-table-row>
      <mo-table-cell class="bryan">Bryan</mo-table-cell>
      <mo-table-cell>25</mo-table-cell>
      <mo-table-cell>bryan@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>George</mo-table-cell>
      <mo-table-cell>40</mo-table-cell>
      <mo-table-cell>georgie@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Louise</mo-table-cell>
      <mo-table-cell>32</mo-table-cell>
      <mo-table-cell>louise@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Augustina</mo-table-cell>
      <mo-table-cell>52</mo-table-cell>
      <mo-table-cell>augustina@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Donna</mo-table-cell>
      <mo-table-cell>39</mo-table-cell>
      <mo-table-cell>donna@email.com</mo-table-cell>
    </mo-table-row>
  </mo-table-body>
</mo-table>

<style>
  /** style every odd row */
  .styled-table mo-table-row:nth-child(even) {
    background-color: var(--mo-color-primary-95, var(--mo-color-secondary-95));
  }
  /** remove vertical padding from cells */
  .styled-table mo-table-cell,
  .styled-table mo-table-head-cell {
    padding: 0 var(--mo-spacing-small);
  }
  /** style specific cell */
  .styled-table mo-table-cell.bryan {
    color: var(--mo-color-brand-orange);
    text-decoration: underline;
  }
</style>

Grid layout

In order to customize the amount of horizontal space each cell takes, you can either set min/max pixes values for their width, or use the CSS grid layout to dictate the span of each column as shown below. The table is split into 12 grid columns, where name takes 2 span, age takes 1 span, email takes 4 span, number takes 3 span and address takes 2 span.

User Age Email Phone Address Bryan 25 bryan@email.com 123 4567 890 Bryan street 4 George 40 georgie@email.com 123 4567 890 Georgetown 21 Louise 32 louise@email.com 123 4567 890 Louiseanna Augustina 52 augustina@email.com 123 4567 890 Augustus 195 Donna 39 donna@email.com 123 4567 890 Donnava
<mo-table class="grid-table">
  <mo-table-head>
    <mo-table-head-cell>User</mo-table-head-cell>
    <mo-table-head-cell>Age</mo-table-head-cell>
    <mo-table-head-cell>Email</mo-table-head-cell>
    <mo-table-head-cell>Phone</mo-table-head-cell>
    <mo-table-head-cell>Address</mo-table-head-cell>
  </mo-table-head>
  <mo-table-body>
    <mo-table-row>
      <mo-table-cell>Bryan</mo-table-cell>
      <mo-table-cell>25</mo-table-cell>
      <mo-table-cell>bryan@email.com</mo-table-cell>
      <mo-table-cell>123 4567 890</mo-table-cell>
      <mo-table-cell>Bryan street 4</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>George</mo-table-cell>
      <mo-table-cell>40</mo-table-cell>
      <mo-table-cell>georgie@email.com</mo-table-cell>
      <mo-table-cell>123 4567 890</mo-table-cell>
      <mo-table-cell>Georgetown 21</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Louise</mo-table-cell>
      <mo-table-cell>32</mo-table-cell>
      <mo-table-cell>louise@email.com</mo-table-cell>
      <mo-table-cell>123 4567 890</mo-table-cell>
      <mo-table-cell>Louiseanna</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Augustina</mo-table-cell>
      <mo-table-cell>52</mo-table-cell>
      <mo-table-cell>augustina@email.com</mo-table-cell>
      <mo-table-cell>123 4567 890</mo-table-cell>
      <mo-table-cell>Augustus 195</mo-table-cell>
    </mo-table-row>
    <mo-table-row>
      <mo-table-cell>Donna</mo-table-cell>
      <mo-table-cell>39</mo-table-cell>
      <mo-table-cell>donna@email.com</mo-table-cell>
      <mo-table-cell>123 4567 890</mo-table-cell>
      <mo-table-cell>Donnava</mo-table-cell>
    </mo-table-row>
  </mo-table-body>
</mo-table>

<style>
  .grid-table {
    overflow: scroll;
  }

  .grid-table mo-table-head,
  .grid-table mo-table-row {
    display: grid;
    grid-template-columns: repeat(12, minmax(50px, 1fr));
    width: 100%;
  }

  .grid-table mo-table-head mo-table-head-cell:nth-child(1),
  .grid-table mo-table-row mo-table-cell:nth-child(1) {
    grid-column: span 2 / span 2;
  }

  .grid-table mo-table-head mo-table-head-cell:nth-child(2),
  .grid-table mo-table-row mo-table-cell:nth-child(2) {
    grid-column: span 1 / span 1;
  }

  .grid-table mo-table-head mo-table-head-cell:nth-child(3),
  .grid-table mo-table-row mo-table-cell:nth-child(3) {
    grid-column: span 4 / span 4;
  }

  .grid-table mo-table-head mo-table-head-cell:nth-child(4),
  .grid-table mo-table-row mo-table-cell:nth-child(4) {
    grid-column: span 3 / span 3;
  }

  .grid-table mo-table-head mo-table-head-cell:nth-child(5),
  .grid-table mo-table-row mo-table-cell:nth-child(5) {
    grid-column: span 2 / span 2;
  }
</style>
import { MOTable } from '@metsooutotec/modes-web-components/dist/react';

const App = () => (
  <MOTable>
    <MOTableHead>
      <MOTableHeadCell>User</MOTableHeadCell>
      <MOTableHeadCell>Age</MOTableHeadCell>
      <MOTableHeadCell>Email</MOTableHeadCell>
    </MOTableHead>
    <MOTableBody>
      <MOTableRow>
        <MOTableCell>Bryan</MOTableCell>
        <MOTableCell>25</MOTableCell>
        <MOTableCell>bryan@email.com</MOTableCell>
      </MOTableRow>
      {...}
    </MOTableBody>
  </MOTable>
);

Selection

To manage selection on an <mo-table>, utilise the selects attribute on <mo-table>. Each <mo-table-row> has a value attribute which, by default, corresponds to its index in the table, and these values tell <mo-table> which <mo-table-row>s are selected. The selected items can be manually applied via the selected property on the table.

Single

When the attribute selects is set to “single”, the <mo-table> will manage a single selection in the array value of selected.

User Age Email Bryan 25 bryan@email.com George 40 georgie@email.com Louise 32 louise@email.com Augustina 52 augustina@email.com Donna 39 donna@email.com
<mo-table size="m" selects="single" selected='["row1"]' style="height: 200px" id="single-select">
  <mo-table-head>
    <mo-table-head-cell>User</mo-table-head-cell>
    <mo-table-head-cell>Age</mo-table-head-cell>
    <mo-table-head-cell>Email</mo-table-head-cell>
  </mo-table-head>
  <mo-table-body>
    <mo-table-row value="row1">
      <mo-table-cell>Bryan</mo-table-cell>
      <mo-table-cell>25</mo-table-cell>
      <mo-table-cell>bryan@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row2">
      <mo-table-cell>George</mo-table-cell>
      <mo-table-cell>40</mo-table-cell>
      <mo-table-cell>georgie@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row3">
      <mo-table-cell>Louise</mo-table-cell>
      <mo-table-cell>32</mo-table-cell>
      <mo-table-cell>louise@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row4">
      <mo-table-cell>Augustina</mo-table-cell>
      <mo-table-cell>52</mo-table-cell>
      <mo-table-cell>augustina@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row5">
      <mo-table-cell>Donna</mo-table-cell>
      <mo-table-cell>39</mo-table-cell>
      <mo-table-cell>donna@email.com</mo-table-cell>
    </mo-table-row>
  </mo-table-body>
</mo-table>

<script>
  const table = document.getElementById('single-select');
  table.addEventListener('mo-change', e => {});
</script>

Multiple

When the attribute selects is set to “multiple”, the <mo-table> will manage a selection in the array value of selected in via a presence toggle. Additionally, an <mo-table-checkbox-cell> will be created in the <mo-table-head> in order to select/deselect all items in the <mo-table>.

User Age Email Bryan 25 bryan@email.com George 40 georgie@email.com Louise 32 louise@email.com Augustina 52 augustina@email.com Donna 39 donna@email.com
<mo-table id="multiple-table" selects="multiple" selected='["row1"]' style="height: 200px">
  <mo-table-head>
    <mo-table-head-cell>User</mo-table-head-cell>
    <mo-table-head-cell>Age</mo-table-head-cell>
    <mo-table-head-cell>Email</mo-table-head-cell>
  </mo-table-head>
  <mo-table-body>
    <mo-table-row value="row1">
      <mo-table-cell>Bryan</mo-table-cell>
      <mo-table-cell>25</mo-table-cell>
      <mo-table-cell>bryan@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row2">
      <mo-table-cell>George</mo-table-cell>
      <mo-table-cell>40</mo-table-cell>
      <mo-table-cell>georgie@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row3">
      <mo-table-cell>Louise</mo-table-cell>
      <mo-table-cell>32</mo-table-cell>
      <mo-table-cell>louise@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row4">
      <mo-table-cell>Augustina</mo-table-cell>
      <mo-table-cell>52</mo-table-cell>
      <mo-table-cell>augustina@email.com</mo-table-cell>
    </mo-table-row>
    <mo-table-row value="row5">
      <mo-table-cell>Donna</mo-table-cell>
      <mo-table-cell>39</mo-table-cell>
      <mo-table-cell>donna@email.com</mo-table-cell>
    </mo-table-row>
  </mo-table-body>
</mo-table>

<script>
  const table = document.getElementById('multiple-table');
  // Always escape HTML for text arguments!
  function escapeHtml(html) {
    const div = document.createElement('div');
    div.textContent = html;
    return div.innerHTML;
  }

  // Custom function to emit toast notifications
  function notify(message, variant = 'primary', icon = 'info', duration = 3000) {
    const alert = Object.assign(document.createElement('mo-alert'), {
      variant,
      closable: true,
      duration: duration,
      innerHTML: `
        <mo-icon name="${icon}" slot="icon"></mo-icon>
        ${escapeHtml(message)}
      `
    });

    document.body.append(alert);
    return alert.toast();
  }
  table.addEventListener('mo-change', e => {
    notify(`Current selection: ${e.target.selected}`);
  });
</script>
<style>
  /** Show toasts in the bottom right corner instead of the default top right. */
  .mo-toast-stack {
    bottom: 0;
    top: auto;
  }
</style>

Virtualized

For large amounts of data, the <mo-table> can be virtualized to easily add table rows by using properties. Enable the scroller property to make the table scrollable, and make sure to specify a height in the mo-table’s inline styles.

Listing id Date Price
<mo-table id="table-virtualized-demo" style="height: 200px" scroller>
  <mo-table-head>
    <mo-table-head-cell>Listing id</mo-table-head-cell>
    <mo-table-head-cell>Date</mo-table-head-cell>
    <mo-table-head-cell>Price</mo-table-head-cell>
  </mo-table-head>
</mo-table>
<script type="module">
  function randomDate(start, end) {
    return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
  }
  function getRandomInt(max) {
    return Math.ceil(Math.random() * max);
  }
  function generateId() {
    return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
      (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
    );
  }
  const initItems = count => {
    const total = count;
    const items = [];
    while (count) {
      count--;
      items.push({
        id: generateId().substring(16),
        index: total - count,
        date: randomDate(new Date(2023, 1, 1), new Date()).toLocaleDateString('en-us', {
          year: 'numeric',
          month: 'short',
          day: 'numeric'
        }),
        price: getRandomInt(10000)
      });
    }
    return items;
  };
  const initTable = () => {
    const table = document.querySelector('#table-virtualized-demo');
    table.items = initItems(500);

    table.renderItem = (item, index) => {
      const cell1 = document.createElement('mo-table-cell');
      const cell2 = document.createElement('mo-table-cell');
      const cell3 = document.createElement('mo-table-cell');
      cell1.textContent = `#${item.index}: ${item.id}`;
      cell2.textContent = `${item.date}`;
      cell3.textContent = `${item.price}`;
      return [cell1, cell2, cell3];
    };
  };
  customElements.whenDefined('mo-table').then(() => {
    initTable();
  });
</script>

Usage

The virtualized table takes items as either a property or a JSON-encoded string, an array of type Record, where the key is a string and the value can be whatever you’d like. items is then fed into the renderItem method, which takes an item and its index as parameters and renders the <mo-table-row> for each item.

For example:

const renderItem = (item: Item, index: number): TemplateResult => {
  return html`
    <mo-table-cell>Row Item Alpha ${item.name}</mo-table-cell>
    <mo-table-cell>Row Item Alpha ${item.date}</mo-table-cell>
    <mo-table-cell>Row Item Alpha ${index}</mo-table-cell>
  `;
};

renderItem is then included as a property of <mo-table>, along with the items, to render a full <mo-table> without excessive manual HTML writing.

You can also render a different cell at a particular index by doing something like below:

const renderItem = (item: Item, index: number): TemplateResult => {
  if (index === 15) {
    return html` <mo-table-cell style="text-align: center">Custom Row</mo-table-cell> `;
  }
  return html`
    <mo-table-cell>Row Item ${item.name}</mo-table-cell>
    <mo-table-cell>Row Item ${item.date}</mo-table-cell>
    <mo-table-cell>Row Item ${index}</mo-table-cell>
  `;
};

Pagination

When the attribute pagination is enabled the tables items will be split on to multiple pages. Use the rowsPerPage and currentPage attributes to customize pagination behavior. If you want to enable selection alongside pagination, you must ensure each row has a unique value. This should be done using the itemValue attribute, as shown below:

Listing id Date Price
Selected: [ ]
<div>
  <mo-table selects="multiple" rowsPerPage="10" pagination paginationSkipButtons id="table-pagination-demo">
    <mo-table-head>
      <mo-table-head-cell>Listing id</mo-table-head-cell>
      <mo-table-head-cell>Date</mo-table-head-cell>
      <mo-table-head-cell sortable sort-key="price">Price</mo-table-head-cell>
    </mo-table-head>
  </mo-table>
  <pre class="selection">Selected: [ ]</pre>
</div>
<script type="module">
  function randomDate(start, end) {
    return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
  }
  function getRandomInt(max) {
    return Math.ceil(Math.random() * max);
  }
  const initItems = count => {
    const total = count;
    const items = [];
    while (count) {
      count--;
      items.push({
        id: crypto.randomUUID().substring(24),
        index: total - count,
        date: randomDate(new Date(2023, 1, 1), new Date()).toLocaleDateString('en-us', {
          year: 'numeric',
          month: 'short',
          day: 'numeric'
        }),
        price: getRandomInt(10000)
      });
    }
    return items;
  };

  let items = initItems(456);

  const initTable = () => {
    const table = document.querySelector('#table-pagination-demo');
    table.itemValue = (item, index) => item.id;
    table.items = items;
    table.renderItem = (item, index) => {
      const cell1 = document.createElement('mo-table-cell');
      const cell2 = document.createElement('mo-table-cell');
      const cell3 = document.createElement('mo-table-cell');
      cell1.textContent = `#${item.index}: ${item.id}`;
      cell2.innerHTML = `<div style="display: flex; align-items: center; gap: 8px;"><mo-icon name="calendar"></mo-icon> ${item.date}</div>`;
      cell3.textContent = `${item.price}`;
      return [cell1, cell2, cell3];
    };
    table.addEventListener('mo-change', event => {
      const selected = event.target.nextElementSibling;
      selected.textContent = `Selected: ${JSON.stringify(event.target.selected, null, ' ')}`;
    });
    table.addEventListener('mo-sorted', event => {
      const { sortDirection, sortKey } = event.detail;
      const sortedItems = table.items.sort((a, b) => {
        const first = a[sortKey];
        const second = b[sortKey];
        return sortDirection === 'desc' ? first - second : second - first;
      });
      table.items = [...sortedItems];
    });
  };
  customElements.whenDefined('mo-table').then(() => {
    initTable();
  });
</script>

Selection

By default the selected property will surface an array of item indices that are currently selected. However, when making a selection on a virtualized table, it can be useful to track selection as something other than indices. To do so, set a custom method for the itemValue property. The itemValue method accepts an item and its index as arguments and should return the value you would like to track in the selected property.

ID Date Price
Selected: [ ]
<mo-table id="table-item-value-demo" style="height: 200px" scroller="true" selects="multiple">
  <mo-table-head>
    <mo-table-head-cell>ID</mo-table-head-cell>
    <mo-table-head-cell>Date</mo-table-head-cell>
    <mo-table-head-cell>
      <span style="width: 100%; text-align: right;">
        Price
      </span>
    </mo-table-head-cell>
  </mo-table-head>
</mo-table>
<pre class="selection">Selected: [ ]</pre>
<script type="module">
  function randomDate(start, end) {
    return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
  }
  function getRandomInt(max) {
    return Math.ceil(Math.random() * max);
  }
  const initItems = count => {
    const total = count;
    const items = [];
    while (count) {
      count--;
      items.push({
        id: crypto.randomUUID().substring(24),
        index: total - count,
        date: randomDate(new Date(2023, 1, 1), new Date()).toLocaleDateString('en-us', {
          year: 'numeric',
          month: 'short',
          day: 'numeric'
        }),
        price: getRandomInt(10000)
      });
    }
    return items;
  };

  const initTable = () => {
    const table = document.querySelector('#table-item-value-demo');
    table.itemValue = (item, index) => item.id;
    table.items = initItems(50);

    table.renderItem = (item, index) => {
      const cell1 = document.createElement('mo-table-cell');
      const cell2 = document.createElement('mo-table-cell');
      const cell3 = document.createElement('mo-table-cell');
      cell1.textContent = `#${item.index}: ${item.id}`;
      cell2.innerHTML = `<div style="display: flex; align-items: center; gap: 8px;"><mo-icon name="calendar"></mo-icon> ${item.date}</div>`;
      cell3.textContent = `$ ${item.price}`;
      cell3.style.width = "100%";
      cell3.style.textAlign = "right";
      cell3.style.fontVariantNumeric = "tabular-nums";
      return [cell1, cell2, cell3];
    };

    table.addEventListener('mo-change', event => {
      const selected = event.target.nextElementSibling;
      selected.textContent = `Selected: ${JSON.stringify(event.target.selected, null, ' ')}`;
    });
  };
  customElements.whenDefined('mo-table').then(() => {
    initTable();
  });
</script>

Sorting

The virtualized table supports sorting its elements.

For each table column you want to sort, use the sortable attribute in its respective <mo-table-head-cell>. sort-direction = "asc"|"desc" specifies the direction of the sorting, in either ascending or descending order, respectively. The mo-sorted event listener on <mo-table> can be utilized to specify a method to fire when the <mo-table-head-cell> dispatches the mo-sorted event. To specify which aspect of an item you’d like to sort by, use the sort-key attribute.

Index and Id Date Status Price (sortable)
<mo-table id="sorted-virtualized-table" style="height: 200px" scroller="true">
  <mo-table-head>
    <mo-table-head-cell sortable sort-key="index">Index and Id</mo-table-head-cell>
    <mo-table-head-cell>Date</mo-table-head-cell>
    <mo-table-head-cell>Status</mo-table-head-cell>
    <mo-table-head-cell sortable sort-key="price">Price (sortable)</mo-table-head-cell>
  </mo-table-head>
</mo-table>
<script type="module">
  function randomDate(start, end) {
    return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
  }
  function getRandomInt(max) {
    return Math.ceil(Math.random() * max);
  }
  const initItems = count => {
    const total = count;
    const items = [];
    const statuses = ['Open', 'Closed', 'In progress'];
    while (count) {
      count--;
      items.push({
        id: crypto.randomUUID().substring(24),
        index: total - count,
        status: statuses[Math.floor(Math.random() * statuses.length)],
        date: randomDate(new Date(2023, 1, 1), new Date()).toLocaleDateString('en-us', {
          year: 'numeric',
          month: 'short',
          day: 'numeric'
        }),
        price: getRandomInt(10000)
      });
    }
    return items;
  };

  let items = initItems(50);

  const initTable = () => {
    const table = document.querySelector('#sorted-virtualized-table');

    table.items = items;

    table.renderItem = (item, index) => {
      const cell1 = document.createElement('mo-table-cell');
      const cell2 = document.createElement('mo-table-cell');
      const cell3 = document.createElement('mo-table-cell');
      const cell4 = document.createElement('mo-table-cell');
      function getVariant(status) {
        if (status === 'Open') {
          return 'success';
        } else if (status === 'Closed') {
          return 'alert';
        } else {
          return 'warning';
        }
      }
      cell1.textContent = `#${item.index}: ${item.id}`;
      cell2.innerHTML = `<div style="display: flex; align-items: center; gap: 8px;"><mo-icon name="calendar"></mo-icon> ${item.date}</div>`;
      cell3.innerHTML = `<mo-badge variant=${getVariant(item.status)}>${item.status}</mo-badge>`;
      cell4.textContent = `${item.price}`;
      return [cell1, cell2, cell3, cell4];
    };
    table.addEventListener('mo-sorted', event => {
      const { sortDirection, sortKey } = event.detail;
      const sortedItems = table.items.sort((a, b) => {
        const first = a[sortKey];
        const second = b[sortKey];
        return sortDirection === 'desc' ? first - second : second - first;
      });
      table.items = [...sortedItems];
    });
  };

  customElements.whenDefined('mo-table').then(() => {
    initTable();
  });
</script>

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/table/table.js';

To import this component as a React component:

import MOTable from '@metsooutotec/modes-web-components/dist/react/table/';

To import this component using a script tag:

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

Slots

Name Description
(default) The table’s content.
(default) The table’s content.

Learn more about using slots.

Properties

Name Description Reflects Type Default
selects Whether the Table allows users to select a row or rows, and thus controls whether or not the Table also renders checkboxes. undefined | 'single' | 'multiple' -
selected An array of values that have been selected. string[] []
items The content of the rows rendered by the virtualized table. The key is the value of the mo-table-row, and the value is the mo-table-row’s content (not the row itself). Record[] []
itemValue The value of an item. By default, it is set to the index of the mo-table-row. - -
scroller Whether or not the virtualized table has a scroll bar. If this is set to true, make sure to specify a height in the mo-table’s inline styles. boolean false
pagination Whether the table rows should be paginated. boolean false
paginationSkipButtons
pagination-skip-buttons
Whether to show first and last page button for pagination. boolean false
currentPage The current page of the pagination. Defaults to first page (index 0) if not defined. number | undefined undefined
rowsPerPage Whether the table rows should be paginated. Defaults to 10 rows per page if left undefined. number | undefined undefined
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
mo-sorted onMoSorted Emitted when a header cell is clicked and the column is sorted. -
mo-change onMoChange Emitted when the content or selection of a virtualized table changes. -
mo-page-change onMoPageChange Emitted when the page of the pagination changes. -

Learn more about events.