Data table

The data table can be used for displaying data in a structured form. It can be extended with functions and various kinds of content based on the use case.

Data tables meant to display big chunks of data enabling you to include certain data manipulation elements alongside the data itself.

Component consists of 2 elements: flix-data-table-wrapper and flix-data-table itself. Available class modifiers for both of them presented in tables bellow:

Modifiers

Wrapper modifiers

flix-data-table-wrapper--collapsed
makes table width adapt to it's contents
flix-data-table-wrapper--responsive
triggers a responsive horizontal scroll on screens bellow `sm` breakpoint
flix-data-table-wrapper--scrollable
creates a scrollable table wrapper

Table modifiers

flix-data-table--small
a smaller table with less paddings in the cells
flix-data-table--sticky-header
makes table header sticky
flix-data-table--plain
removes "zebra" coloring for rows

Examples

Data table with a fixed header and selectable rows

In order to make things look nice you need to ensure 2 things:

  • trigger a "scrollable" variation of flix-data-table-wrapper and make sure to specify it's height;
  • add flix-data-table--sticky-header modifier to data-table element.

Selectable rows:

  • Highlight the selected row by adding the flix-data-table__row--selected modifier;
  • Add aria-selected="true|false" so screen readers can announce the row status correctly.

Checkout provided example for more info.

Trips departing from your location
Departure Price Seats Links
07:05 h22.99€29Details
07:00 h22.99€29Details
06:50 h22.99€29Details
06:35 h22.99€29Details
06:25 h22.99€29Details
06:05 h22.99€29Details
<div class="flix-data-table-wrapper flix-data-table-wrapper--scrollable" style="height:246px">
  <table class="flix-data-table flix-data-table--sticky-header"><caption>Trips departing from your location</caption><thead class="flix-data-table__header"><tr><th scope="col">
          <div class="flix-checkbox flix-checkbox--sm">
            <input class="flix-checkbox__input" type="checkbox" id="example-table-checkbox-all" value="select-all"/>
            <label class="flix-checkbox__label" for="example-table-checkbox-all">
              <span class="flix-sr-only">Select row</span>
            </label>
          </div>
        </th><th scope="col">
          <span>Departure</span>
          <button aria-label="Sort rows by departure time" class="flix-data-table__header-btn" type="button">
            <i class="flix-icon flix-icon-arrow-big-down" aria-hidden="true"></i>
          </button>
        </th><th scope="col">
          <span>Price</span>
          <button aria-label="Sort rows by price" class="flix-data-table__header-btn" type="button">
            <i class="flix-icon flix-icon-expand" aria-hidden="true"></i>
          </button>
        </th><th scope="col">
          <span>Seats</span>
          <button aria-label="Sort rows by available seats" class="flix-data-table__header-btn" type="button">
            <i class="flix-icon flix-icon-expand" aria-hidden="true"></i>
          </button>
        </th><th scope="col">
          <span>Links</span>
          <button aria-label="Sort rows by links" class="flix-data-table__header-btn" type="button">
            <i class="flix-icon flix-icon-expand" aria-hidden="true"></i>
          </button>
        </th></tr></thead><tbody><tr class="flix-data-table__row" aria-selected="false"><td>
          <div class="flix-checkbox flix-checkbox--sm">
            <input class="flix-checkbox__input" type="checkbox" id="example-table-checkbox-1" value="select-1"/>
            <label class="flix-checkbox__label" for="example-table-checkbox-1">
              <span class="flix-sr-only">Select row</span>
            </label>
          </div>
        </td><td scope="row">07:05 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr><tr class="flix-data-table__row flix-data-table__row--selected" aria-selected="true"><td>
          <div class="flix-checkbox flix-checkbox--sm">
            <input class="flix-checkbox__input" type="checkbox" id="example-table-checkbox-2" checked="" value="select-2"/>
            <label class="flix-checkbox__label" for="example-table-checkbox-2">
              <span class="flix-sr-only">Select row</span>
            </label>
          </div>
        </td><td scope="row">07:00 h</td><td>22.99€</td><td>29</td><td><a class="flix-link flix-element-has-hint" href="#" data-hint="Uh oh... I am a hint">Details</a></td></tr><tr class="flix-data-table__row" aria-selected="false"><td>
          <div class="flix-checkbox flix-checkbox--sm">
            <input class="flix-checkbox__input" type="checkbox" id="example-table-checkbox-3" value="select-3"/>
            <label class="flix-checkbox__label" for="example-table-checkbox-3">
              <span class="flix-sr-only">Select row</span>
            </label>
          </div>
        </td><td scope="row">06:50 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr><tr class="flix-data-table__row" aria-selected="false"><td>
          <div class="flix-checkbox flix-checkbox--sm">
            <input class="flix-checkbox__input" type="checkbox" id="example-table-checkbox-4" value="select-4"/>
            <label class="flix-checkbox__label" for="example-table-checkbox-4">
              <span class="flix-sr-only">Select row</span>
            </label>
          </div>
        </td><td scope="row">06:35 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr><tr class="flix-data-table__row" aria-selected="false"><td>
          <div class="flix-checkbox flix-checkbox--sm">
            <input class="flix-checkbox__input" type="checkbox" id="example-table-checkbox-5" value="select-5"/>
            <label class="flix-checkbox__label" for="example-table-checkbox-5">
              <span class="flix-sr-only">Select row</span>
            </label>
          </div>
        </td><td scope="row">06:25 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr><tr class="flix-data-table__row" aria-selected="false"><td>
          <div class="flix-checkbox flix-checkbox--sm">
            <input class="flix-checkbox__input" type="checkbox" id="example-table-checkbox-6" value="select-6"/>
            <label class="flix-checkbox__label" for="example-table-checkbox-6">
              <span class="flix-sr-only">Select row</span>
            </label>
          </div>
        </td><td scope="row">06:05 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr></tbody></table>
</div>

Smaller plain data table with pagination

You can associate a pager component to the data table to create a paginated table. To do so both components must be wrapper with a flix-data-table-wrapper container to ensure proper spacing and alignment.

In this case, if the data table pagination action happens inside of the same page, you should use pagination with buttons instead of links. Activating the buttons will update the table state with new items.

As a good practice for accessibility you should announce any live changes on the table, you can do so by making the table a live region. In this case, adding aria-live="polite" will ensure the screen readers will announce that the table has been updated when pagination occurs.

Additionally, adding a table caption informing which page is currently active is advised:

Trips: Page 2 of 5
DeparturePriceSeatsLinks
07:00 h22.99€29Details
08:00 h22.99€29Details
09:05 h22.99€29Details
09:30 h22.99€29Details
<div class="flix-data-table-controls">
  <div class="flix-data-table-wrapper">
    <table aria-live="polite" class="flix-data-table flix-data-table--small flix-data-table--plain"><caption>Trips: Page 2 of 5</caption><thead class="flix-data-table__header"><tr><th scope="col">Departure</th><th scope="col">Price</th><th scope="col">Seats</th><th scope="col">Links</th></tr></thead><tbody><tr class="flix-data-table__row"><td scope="row">07:00 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr><tr class="flix-data-table__row"><td scope="row">08:00 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr><tr class="flix-data-table__row"><td scope="row">09:05 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr><tr class="flix-data-table__row"><td scope="row">09:30 h</td><td>22.99€</td><td>29</td><td><a class="flix-link" href="#">Details</a></td></tr></tbody></table>
  </div>
  <nav class="flix-pager" aria-label="Data table pagination">
      <ul class="flix-pager__list">
        <li class="flix-pager__item">
          <button class="flix-pager__link flix-pager__link--prev flix-pager__link--disabled" aria-disabled="true" disabled="">
            <span class="flix-sr-only">Previous page</span>
          </button>
        </li>
        <li class="flix-pager__item">
          <button type="button" class="flix-pager__link">
            1
          </button>
        </li>
        <li class="flix-pager__item">
          <button type="button" class="flix-pager__link" aria-current="true">
            2
          </button>
        </li>
        <li class="flix-pager__item">
          <button type="button" class="flix-pager__link">
            3
          </button>
        </li>
        <li class="flix-pager__item">
          <button type="button" class="flix-pager__link">
            4
          </button>
        </li>
        <li class="flix-pager__item">
          <button type="button" class="flix-pager__link">
            5
          </button>
        </li>
        <li class="flix-pager__item">
          <button type="button" class="flix-pager__link flix-pager__link--next">
            <span class="flix-sr-only">Next page</span>
          </button>
        </li>
      </ul>
    </nav>
</div>
Available space per trip
DepartureSeatsBikes
06:05 h4011
07:00 h382
08:10 h296
10:15 h292
12:35 h140
Totals15021
<div class="flix-data-table-wrapper flix-data-table-wrapper--collapsed">
  <table class="flix-data-table flix-data-table--small"><caption>Available space per trip</caption><thead class="flix-data-table__header"><tr><th scope="col">Departure</th><th scope="col">Seats</th><th scope="col">Bikes</th></tr></thead><tbody><tr class="flix-data-table__row"><td scope="row">06:05 h</td><td>40</td><td>11</td></tr><tr class="flix-data-table__row flix-data-table__row--selected"><td scope="row">07:00 h</td><td>38</td><td>2</td></tr><tr class="flix-data-table__row"><td scope="row">08:10 h</td><td>29</td><td>6</td></tr><tr class="flix-data-table__row"><td scope="row">10:15 h</td><td>29</td><td>2</td></tr><tr class="flix-data-table__row"><td scope="row">12:35 h</td><td>14</td><td>0</td></tr></tbody><tfoot class="flix-data-table__footer"><tr><th scope="col">Totals</th><th scope="col">150</th><th scope="col">21</th></tr></tfoot></table>
</div>

Scopes

The declaration of the scope attribute on the table headings (the th tags) helps people who are using screen readers while they navigate the table. If your table has headers, please include the adequate scope for them.

The scope="col" should be applied to the cells inside the <thead> and identify the data of a column. E.g.: "This column has Prices".

The scope="row" should be applied in header cells that identify the row (if there are any). E.g.: "This row is the 6am ride."