SST - Single Standard for Tables

SST - Single Standard for Tables
Standards

32

8 min.

Definitions

The SST standard defines requirements for the semantics, accessibility, and logic of tables.

Structure and Semantics

Core Table Elements

  • When a table needs a title or brief description, it is provided with <caption>. If present, <caption> is the first element inside <table>. A caption helps explain the table's purpose, but does not by itself guarantee an SEO improvement.
  • <thead> groups rows containing column headings. A browser or document generator may repeat this group in paged print; actual behavior depends on the print engine and page-break settings.
  • One or more <tbody> elements group data rows. Multiple <tbody> groups are used when rows are divided into logical sections. A table has no more than one <thead> and one <tfoot> section.
  • <tfoot> contains summary or total rows. Under the current HTML model, it is placed after the table's row groups; CSS displays it as the table footer group. Older examples that place <tfoot> before <tbody> should not be treated as current markup guidance.
  • <tr> defines a row, <th> a header cell, and <td> a data cell. <th> and <td> must reflect the actual role of the content, not just the desired visual style.

Column Groups

  • <colgroup> represents a group of columns and is placed after <caption> and before the row groups.
  • <col> describes one or more columns within <colgroup>. Its span attribute specifies the number of columns covered by the element.
  • When <colgroup> contains <col> elements, the number of columns is specified with span on <col>. Alternatively, span can be set directly on an empty <colgroup> with no child <col> elements.
  • <col> and <colgroup> are useful for setting column widths and backgrounds. The CSS properties that apply to them are limited; for example, text-align and padding on <col> do not align text or set cell padding.
  • A column background is painted beneath row and cell backgrounds. If a <th> or <td> has an opaque background, the <col> color may not be visible. Column borders set through <col> are displayed only with collapsed borders.

Accessibility

Headers and Cell Relationships

  • In a simple table, column headings use <th scope="col">, and a row heading uses <th scope="row">. The scope attribute associates a header cell with the data it applies to.
  • For headers that cover a group of rows or columns, use scope="rowgroup" and scope="colgroup" when the table structure matches those groups.
  • In complex tables with multi-level or non-adjacent headers, scope alone may not be sufficient. Explicitly associate headers and data cells with unique id values on <th> and corresponding headers values on <td>.
  • Visual styling alone is not enough to establish header-data relationships programmatically. The table structure must be tested with assistive technologies.

Example of simple row and column headers:

<table>
  <caption>Project participants</caption>
  <thead>
    <tr>
      <th scope="col">Field</th>
      <th scope="col">Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">User name</th>
      <td>Alex</td>
    </tr>
  </tbody>
</table>

Styling and the Table Model

Padding, Borders, and Empty Cells

  • Padding is set on <th> and <td> cells. padding on a <tr> row does not control the padding of its cells.
  • border-collapse: collapse combines adjacent cell borders into a shared grid. With border-collapse: separate, borders and the spacing between them are handled separately.
  • empty-cells: show and empty-cells: hide control the display of borders and backgrounds on empty cells only with border-collapse: separate. The property does not remove a cell from the table or define the meaning of missing data.
  • When an absent value matters to the interpretation of the data, provide a clear value or state. An empty cell must not create ambiguity.

Preserving the Table Model

  • <table>, <tr>, <th>, and <td> retain their native table display model when the content genuinely represents rows and columns.
  • Changing a table row's display to flex or grid changes the layout algorithm: the cells in that row no longer participate in the shared table grid, so columns may no longer align across rows.
  • To adapt a table, first configure its native width, content wrapping, and container scrolling. An alternative card layout is appropriate as a separate presentation if header-data relationships and a clear reading order are preserved.

Data Alignment

  • Alignment is set explicitly with CSS rather than assumed from browser default styles.
  • Text values are generally aligned to the start of the line and numeric values to its end to make quantities easier to compare. For RTL support, use logical alignment such as text-align: start and text-align: end instead of unconditional left and right.
  • When values need to be compared by their decimal separators, use dedicated markup or formatting that accounts for the active locale.

Fixed Table Layout

  • table-layout: fixed is suitable when column widths need to be distributed more predictably and the table itself has a specified width other than auto.
  • With the fixed algorithm, column widths are determined first by widths set on <col>, then by widths on cells in the first row; any remaining space is distributed among the other columns.
  • This algorithm depends less on the content of every cell and may simplify layout, but it does not guarantee faster rendering in every interface. Long content may wrap, overflow a cell, or require separate handling.

Responsiveness and Scrolling

  • If a table cannot fit in the available width without losing readability, horizontal scrolling is confined to a separate container with overflow-x: auto. The container width must be constrained by its parent area.
  • The <table> element retains its native table display. display: block is not used as a substitute for an overflow container: changing the display type can disrupt row layout and shared column alignment.
  • Horizontal scrolling must remain discoverable and keyboard-accessible. A separately scrollable area needs a clear accessible name, visible focus, and keyboard focusability when these are not already provided by the browser and the area's contents.
  • -webkit-overflow-scrolling: touch is not a baseline requirement for accelerated scrolling on iOS and iPadOS 13 or later. On iPhone, the property can create a stacking context; retain it only when it is demonstrably needed for older target systems and after checking for side effects.
  • On narrow screens, test not only scrolling but also access to every column, heading, value, and focusable element inside the cells.

Example of a scrollable container:

<div
  class="table-scroll"
  role="region"
  aria-label="Monthly sales summary"
  tabindex="0"
>
  <table class="data-table data-table--wide">
    <caption>Monthly sales summary</caption>
    <colgroup>
      <col class="data-table__month">
      <col span="2" class="data-table__metrics">
    </colgroup>
    <thead>
      <tr>
        <th scope="col">Month</th>
        <th scope="col">Orders</th>
        <th scope="col">Revenue</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <th scope="row">January</th>
        <td>120</td>
        <td>360,000 ₽</td>
      </tr>
      <tr>
        <th scope="row">February</th>
        <td>145</td>
        <td>435,000 ₽</td>
      </tr>
    </tbody>
    <tfoot>
      <tr>
        <th scope="row">Total</th>
        <td>265</td>
        <td>795,000 ₽</td>
      </tr>
    </tfoot>
  </table>
</div>
.table-scroll {
  max-width: 100%;
  overflow-x: auto;
}

.data-table {
  width: 100%;
  border-collapse: collapse;
}

.data-table--fixed {
  table-layout: fixed;
}

.data-table--separate {
  border-collapse: separate;
  empty-cells: hide;
}

.data-table--wide {
  min-width: 42rem;
}

.data-table__month {
  width: 40%;
}

.data-table__metrics {
  background-color: #f5f5f5;
}

.data-table th,
.data-table td {
  padding: 0.75rem;
  border: 1px solid #ccc;
}

.data-table th {
  text-align: start;
}

.data-table td {
  text-align: end;
}

.table-scroll:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

The data-table--wide class is used only when columns need a defined minimum width; the 42rem value is adjusted to the content. A background set through <col> remains visible unless it is covered by a cell or row background.

Additional States

  • For a long table, headings can remain visible during vertical scrolling by applying position: sticky to <th> cells inside <thead>.
  • Sticky cells need an offset and background, and may need z-index; otherwise, row content may show through or overlap the headings.
  • position: sticky is constrained by the nearest scroll container. When a sticky header is combined with a horizontally scrollable area, test behavior both during page scrolling and inside the container.

Example of sticky headings:

.data-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background-color: #fff;
}

Headers in Print

  • <thead> retains the semantic header group. Print and PDF engines may repeat it when a long table spans multiple pages; verify the result in the target print environment.

Testing

  • Check that the table structure matches the data and that elements appear in the correct order: caption, colgroup, thead, tbody groups, and tfoot.
  • Ensure each row and column has clear headings; test scope or id/headers relationships with a screen reader.
  • Test tables with multiple <tbody> groups, spanning cells, and multi-level headings when those cases are used.
  • On narrow screens, check horizontal scrolling, keyboard access, and that the page itself does not overflow horizontally.
  • Check long content with table-layout: fixed, as well as focus and sticky-header layering when used.
  • Test empty cells with the actual border-collapse value; empty values must not change the meaning of the data.
  • Check print output and header repetition in the target browsers and PDF generators.

SST Checklist

CategoryCore elementsPurpose
Semanticscaption, thead, tbody, tfoot, tr, th, tdConvey data structure and roles
Columnscolgroup, col, spanDefine groups and a limited set of column styles
Accessibilityscope, id, headersAssociate headers with data cells
StylingCell padding, borders, empty-cellsProvide predictable table-grid styling
Layouttable-layout, logical alignmentControl width and make values easier to compare
ResponsivenessContainer with overflow-x: autoKeep wide tables accessible without page overflow
Additional statesSticky headings, printPreserve readability of long tables in target environments

Similar categories:

Similar articles

  • Anatomy of a React component

    My vision for how every React component should look

    421

    8 min.

  • SST - Single Standard for Tabs

    The SST standard defines requirements for the semantics, accessibility, and logic of tabs

    62

    7 min.

  • SSF-U - Single Standard for Fullscreen

    The SSF-U standard defines requirements for the semantics, accessibility, and logic of fullscreen

    248

    2 min.

  • SSA - Single Standard for Accordion

    The SSA standard defines requirements for the semantics, accessibility, and logic of accordion

    258

    2 min.

  • Bad Practices for Websites

    An Analysis of Critical Web Design Mistakes. Why Sliders, Autoplay, and Slow-Loading Pages Reduce Conversion Rates and Rankings on Google

    232

    2 min.

  • SSP - Single Standard for Pagination

    The SSP standard defines requirements for the semantics, accessibility, and logic of pagination

    240

    1 min.

  • All articles

Contact me