Skip to content

CKEditor 5 Mangles Table Structure and Makes Tables Inaccessible / Support for Tables with Multi-Level Headers / Allow <tbody> <th> in any column #14911

Description

@jameslpetersen

📝 Provide detailed reproduction steps (if any)

  1. Paste the HTML from tables 1, 2, 3, and 4 (below) into source view of the reference implementation of CKEditor.
  2. Switch out of source view and back into it.

Table 1

This table has a rowgroup header with a colspan.

<table>
    <thead>
    <tr>
        <th scope="col">Col Header 1</th>
        <th scope="col">Col Header 2</th>
        <th scope="col">Col Header 3</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th scope="rowgroup" colspan="3">Rowgroup Header 1</th>
    </tr>
    <tr>
        <th scope="row">Row Header 1</th>
        <td>Data 1,1</td>
        <td>Data 2,1</td>
    </tr>
    </tbody>
</table>

Table 2

This table has two rowgroup headers that have colspans.

<table>
    <thead>
    <tr>
        <th scope="col">Col Header 1</th>
        <th scope="col">Col Header 2</th>
        <th scope="col">Col Header 3</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th scope="rowgroup" colspan="3">Rowgroup Header 1</th>
    </tr>
    <tr>
        <th scope="row">Row Header 1</th>
        <td>Data 1,1</td>
        <td>Data 2,1</td>
    </tr>
    </tbody>
    <tbody>
    <tr>
        <th scope="rowgroup" colspan="3">Rowgroup Header 2</th>
    </tr>
    <tr>
        <th scope="row">Row Header 2</th>
        <td>Data 1,2</td>
        <td>Data 2,2</td>
    </tr>
    <tr>
        <th scope="row">Row Header 3</th>
        <td>Data 1,3</td>
        <td>Data 2,3</td>
    </tr>
    </tbody>
</table>

Table 3

Similar to previous examples, but we've removed the colspan on the rowgroup and replaced with empty td elements. We've also added some row headers to the second column and a tbody block that doesn't have any th with a scope set to rowgroup.

<table>
    <thead>
    <tr>
        <th scope="col">Col Header 1</th>
        <th scope="col">Col Header 2</th>
        <th scope="col">Col Header 3</th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th scope="rowgroup">Rowgroup Header 1</th>
        <td></td>
        <td></td>
    </tr>
    <tr>
        <th scope="row">Row Header 1</th>
        <th scope="row">Row Subheader 1</th>
        <td>Data 1,1</td>
    </tr>
    </tbody>
    <tbody>
    <tr>
        <th scope="row">Row Header 2</th>
        <th scope="row">Row Subheader 2</th>
        <td>Data 1,2</td>
    </tr>
    <tr>
        <th scope="row">Row Header 3</th>
        <th scope="row">Row Subheader 3</th>
        <td>Data 1,3</td>
    </tr>
    </tbody>
    <tbody>
    <tr>
        <th scope="rowgroup">Rowgroup Header 2</th>
        <td></td>
        <td></td>
    </tr>
    <tr>
        <th scope="row">Row Header 4</th>
        <th scope="row">Row Subheader 4</th>
        <td>Data 1,4</td>
    </tr>
    </tbody>
</table>

Table 4

This table is an example from the HTML spec.

<table>
    <colgroup> <col>
    <colgroup> <col> <col> <col>
    <thead>
    <tr> <th> <th>2008 <th>2007 <th>2006
    <tbody>
    <tr> <th scope=rowgroup> Research and development
        <td> $ 1,109 <td> $ 782 <td> $ 712
    <tr> <th scope=row> Percentage of net sales
        <td> 3.4% <td> 3.3% <td> 3.7%
    <tbody>
    <tr> <th scope=rowgroup> Selling, general, and administrative
        <td> $ 3,761 <td> $ 2,963 <td> $ 2,433
    <tr> <th scope=row> Percentage of net sales
        <td> 11.6% <td> 12.3% <td> 12.6%
</table>

✔️ Expected result

CKEditor does not alter the table markup.

❌ Actual result

Table 1

CKEditor has moved the parent row for "Rowgroup Header 1" into the thead element, which makes the table inaccessible to screen readers.

<table>
    <thead>
    <tr>
        <th scope="col">
            Col Header 1
        </th>
        <th scope="col">
            Col Header 2
        </th>
        <th scope="col">
            Col Header 3
        </th>
    </tr>
    <tr>
        <th colspan="3" scope="rowgroup">
            Rowgroup Header 1
        </th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th scope="row">
            Row Header 1
        </th>
        <td>
            Data 1,1
        </td>
        <td>
            Data 2,1
        </td>
    </tr>
    </tbody>
</table>

Table 2

CKEditor has moved all the parent rows for rowgroup headers into the thead element. It has also put all the rows after the thead block into one tbody block. This makes the table inaccessible to screen readers and is a loss of data, since we can no longer reconstruct the original table due to loss of the tbody blocks.

<table>
    <thead>
    <tr>
        <th scope="col">
            Col Header 1
        </th>
        <th scope="col">
            Col Header 2
        </th>
        <th scope="col">
            Col Header 3
        </th>
    </tr>
    <tr>
        <th colspan="3" scope="rowgroup">
            Rowgroup Header 1
        </th>
    </tr>
    <tr>
        <th colspan="3" scope="rowgroup">
            Rowgroup Header 2
        </th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th scope="row">
            Row Header 1
        </th>
        <td>
            Data 1,1
        </td>
        <td>
            Data 2,1
        </td>
    </tr>
    <tr>
        <th scope="row">
            Row Header 2
        </th>
        <td>
            Data 1,2
        </td>
        <td>
            Data 2,2
        </td>
    </tr>
    <tr>
        <th scope="row">
            Row Header 3
        </th>
        <td>
            Data 1,3
        </td>
        <td>
            Data 2,3
        </td>
    </tr>
    </tbody>
</table>

Table 3

CKEditor has not moved all the parent rows for rowgroup headers into the thead element, but has put all the rows after the thead block into one tbody block. This causes data loss, since we can no longer reconstruct the original table due to loss of the tbody blocks, and makes the table inaccessible to screen readers. CKEditor has also turned row headers in the second column to td elements with a scope attribute, which is invalid, and causes further accessibility issues.

<table>
    <thead>
    <tr>
        <th scope="col">
            Col Header 1
        </th>
        <th scope="col">
            Col Header 2
        </th>
        <th scope="col">
            Col Header 3
        </th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th scope="rowgroup">
            Rowgroup Header 1
        </th>
        <td>
            &nbsp;
        </td>
        <td>
            &nbsp;
        </td>
    </tr>
    <tr>
        <th scope="row">
            Row Header 1
        </th>
        <td scope="row">
            Row Subheader 1
        </td>
        <td>
            Data 1,1
        </td>
    </tr>
    <tr>
        <th scope="row">
            Row Header 2
        </th>
        <td scope="row">
            Row Subheader 2
        </td>
        <td>
            Data 1,2
        </td>
    </tr>
    <tr>
        <th scope="row">
            Row Header 3
        </th>
        <td scope="row">
            Row Subheader 3
        </td>
        <td>
            Data 1,3
        </td>
    </tr>
    <tr>
        <th scope="rowgroup">
            Rowgroup Header 2
        </th>
        <td>
            &nbsp;
        </td>
        <td>
            &nbsp;
        </td>
    </tr>
    <tr>
        <th scope="row">
            Row Header 4
        </th>
        <td scope="row">
            Row Subheader 4
        </td>
        <td>
            Data 1,4
        </td>
    </tr>
    </tbody>
</table>

Table 4

CKEditor has added inline styles to col elements (strange), put all the rows after the thead block into one tbody block (again, potential data loss and makes the table inaccessible to screen readers). I'm not sure what the practical implications of this next quirk are, but I want to note it. CKEditor has added a non-breaking space character to an empty th tag. I don't think non-breaking spaces are ASCII whitespace. This means that the header cell is non-empty and user agents (including screen readers) should add it to the header list for the cells beneath it, according to the spec.

<table class="ck-table-resized">
    <colgroup><col style="width:25%;"><col style="width:25%;"><col style="width:25%;"><col style="width:25%;"></colgroup><colgroup><col><col><col></colgroup>
    <thead>
    <tr>
        <th>
            &nbsp;
        </th>
        <th>
            2008
        </th>
        <th>
            2007
        </th>
        <th>
            2006
        </th>
    </tr>
    </thead>
    <tbody>
    <tr>
        <th scope="rowgroup">
            Research and development
        </th>
        <td>
            $ 1,109
        </td>
        <td>
            $ 782
        </td>
        <td>
            $ 712
        </td>
    </tr>
    <tr>
        <th scope="row">
            Percentage of net sales
        </th>
        <td>
            3.4%
        </td>
        <td>
            3.3%
        </td>
        <td>
            3.7%
        </td>
    </tr>
    <tr>
        <th scope="rowgroup">
            Selling, general, and administrative
        </th>
        <td>
            $ 3,761
        </td>
        <td>
            $ 2,963
        </td>
        <td>
            $ 2,433
        </td>
    </tr>
    <tr>
        <th scope="row">
            Percentage of net sales
        </th>
        <td>
            11.6%
        </td>
        <td>
            12.3%
        </td>
        <td>
            12.6%
        </td>
    </tr>
    </tbody>
</table>

❓ Possible solution

Add some kind of data attribute that tells CKEditor to not parse the table. Or just follow the table parsing algorithm from the HTML5 spec.

📃 Other details

  • Browser: Any
  • OS: Any
  • First affected CKEditor version: Unknown, but this is happening in the reference implementation.
  • Installed CKEditor plugins: None

If you'd like to see this fixed sooner, add a 👍 reaction to this post.

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:accessibilityThis issue reports an accessibility problem.domain:v4-compatibilityThis issue reports a CKEditor 4 feature/option that's missing in CKEditor 5.package:tablesquad:coreIssue to be handled by the Core team.support:2An issue reported by a commercially licensed client.type:bugThis issue reports a buggy (incorrect) behavior.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions