How to: Using captions and roles in tables

08 Oct 2025 | By Drupal support team
08 Oct 2025 | By Drupal support team

Use this guide when creating tables in CKEditor 5 that need stacked header sections. These instructions explain how to add titles and section headers correctly while avoiding the CKEditor bug that moves all header cells to the top.

1. Table Caption

The caption gives the table a clear title or label. Screen readers read it first, and it appears at the top. Place it directly after the opening table tag.

<table>
  <caption>Table title (for example: Student Performance Summary)</caption>
  ...
</table>
  • Use captions to describe what the whole table represents.
  • Keep them short and meaningful.
  • Don’t use captions for section headings inside the table.
  • Don’t repeat the same caption across multiple tables.

2. Regular Header Row

The first header row defines your main column headings and sits in the table’s header section.

<thead>
  <tr>
    <th>Subject</th>
    <th>Score</th>
  </tr>
</thead>

3. Data Rows

Normal data rows go inside the body section of the table and use standard cells.

<tbody>
  <tr>
    <td>Math</td>
    <td>80</td>
  </tr>
</tbody>

4. Subheader Rows

CKEditor 5 moves header cells inside the body up to the top of the table. To create “header-like” rows inside the body, use normal cells with the attribute role="columnheader" for column headings or role="rowheader" for row headings.

<tr>
  <td role="columnheader">Term 2</td>
  <td role="columnheader">Results</td>
</tr>

<tr>
  <td role="rowheader">Student A</td>
  <td>85</td>
</tr>

Use role="columnheader" for cells that act as column headers and role="rowheader" for cells that label entire rows. These cells behave like real headers for screen readers but stay correctly inside the body.

5. Complete Example

<table>
  <caption>h1</caption>
  <thead>
    <tr>
      <th>h2</th>
      <th>h3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>c1</td>
      <td>c2</td>
    </tr>
    <tr>
      <td role="columnheader">h4</td>
      <td role="columnheader">h5</td>
    </tr>
    <tr>
      <td role="rowheader">c3</td>
      <td>c4</td>
    </tr>
  </tbody>
</table>

6. Quick Rules

  • Always include a caption as the table title.
  • Use header cells (<th>) only in the top header row.
  • Use role="columnheader" for subheader rows in the body.
  • Use role="rowheader" for row titles in the body.
  • Keep your table structure simple: caption → head → body.
  • Don’t add <th> inside the table body.
  • Don’t duplicate captions or nest tables unnecessarily.

7. Accessibility Reminder

  • Captions are announced first by screen readers.
  • Cells marked with role="columnheader" are treated as column headers.
  • Cells marked with role="rowheader" are treated as row headers.
  • Test navigation with keyboard and screen reader to confirm correct reading order.