Empty Header Helper
Use empty_header when a table column header should appear visually empty, but still needs an accessible label for screen readers.
This is most common for action columns (for example: Edit/Delete buttons).
Why use this helper
- Keeps table headers semantically correct (
<th>with a validscope) - Adds accessible labeling for assistive technology
- Prevents invalid scope values
- Supports utility classes for width/alignment
Method signature
empty_header(*classes, text: nil, scope: 'col')
Arguments
*classes(String | Symbol, splat): Optional CSS classes added to the<th>element.text(String | nil): Optional hidden text label. If present, it renders inside<span class="sr-only">...</span>.scope(String | Symbol): Header scope. Allowed values arecol,row,colgroup, androwgroup.
Validation rules
- You must provide
text. - If argument is blank/nil, the helper raises:
ArgumentError: '`text` must be provided'
- If
scopeis not one of the allowed values, the helper raises:
ArgumentError: 'Scope must be one of: `col`, `row`, `colgroup`, `rowgroup`'
Basic usage in a table
<table class="table"> <thead> <tr> <th scope="col">Name</th> <th scope="col">Status</th> <%= empty_header('w-0 text-nowrap', text: 'Actions') %> </tr> </thead> <tbody> <% @users.each do |user| %> <tr> <td><%= user.name %></td> <td><%= user.status %></td> <td class="text-nowrap"> <%= link_to 'Edit', edit_user_path(user), class: 'btn btn-sm btn-secondary' %> </td> </tr> <% end %> </tbody> </table>
Row header usage
When used for row headers, set scope: 'row':
<%= empty_header(text: 'Row actions', scope: 'row') %>
Accessibility guidance
- Prefer short, descriptive labels like
Actions,Row actions, orSelect row - Keep labels consistent across similar tables
- Do not leave action columns without an accessible header label