Introduction to Table Accessibility
Web accessibility ensures that websites and applications can be used by people with disabilities. When it comes to HTML tables, accessibility is particularly important because tables present complex relationships between data that can be challenging to understand without visual cues.
People using assistive technologies like screen readers need additional context to understand table data properly. Without proper accessibility features, tables can become confusing or even incomprehensible for users with visual impairments.
In this lecture, we'll dive deep into table accessibility features, exploring how to make data tables perceivable, operable, understandable, and robust for all users, regardless of their abilities or the technologies they use to access the web.
Why Table Accessibility Matters
Before diving into specific techniques, let's understand why table accessibility is so important and the challenges tables present to users with disabilities.
Challenges for Screen Reader Users
Screen reader users face several challenges when encountering tables:
- Loss of visual context: They can't quickly scan the table to understand its structure
- Sequential reading: Data is read cell by cell, making it hard to understand relationships
- Header association: Without proper markup, they can't tell which headers apply to which cells
- Navigation difficulty: Moving between cells and finding specific data can be cumbersome
- Complex layouts: Tables with merged cells or nested tables are particularly challenging
Challenges for Keyboard-Only Users
Users who navigate with keyboards instead of mice also face challenges:
- Cell navigation: Moving through large tables cell by cell can be tedious
- Focus visibility: It can be difficult to track which cell has focus
- Interactive elements: Buttons or links within tables need to be properly accessible
Challenges for Users with Low Vision
Low vision users may struggle with:
- Text size and spacing: Tables often use compact layouts that are hard to read when zoomed
- Color contrast: Insufficient contrast between text and background
- Table gridlines: Faint borders can disappear for users with contrast sensitivity issues
Challenges for Mobile and Responsive Design
Tables present unique challenges on small screens:
- Horizontal scrolling: Wide tables can force users to scroll horizontally, losing context
- Column headers: Headers may scroll out of view as users move horizontally
- Row association: It can be difficult to maintain row context when scrolling horizontally
Legal and Ethical Considerations
Beyond the practical challenges, there are legal and ethical reasons to make tables accessible:
- Legal requirements: Many jurisdictions have laws requiring web accessibility (e.g., ADA in the US, EAA in the EU)
- Equal access: All users should have equal access to information
- Inclusive design: Accessible tables often benefit all users, not just those with disabilities
- Professional responsibility: Creating accessible content is part of being a responsible web professional
With these challenges in mind, let's explore the features and techniques that make tables accessible to all users.
Semantic Table Structure for Accessibility
The foundation of table accessibility is proper semantic structure. Using the right HTML elements helps assistive technologies understand and communicate table content effectively.
The <caption> Element
The <caption> element provides a title or brief description for a table. Screen readers announce this caption when users encounter the table, giving them immediate context.
<table>
<caption>Quarterly Sales by Region (2025)</caption>
<!-- Table content -->
</table>
Best practices for captions:
- Keep captions concise but descriptive
- Include the purpose and scope of the table
- Consider including time periods or units of measurement
- Place the caption as the first child of the table element
Table Sections: <thead>, <tbody>, and <tfoot>
These semantic section elements help screen readers identify different parts of the table:
<table>
<caption>Quarterly Sales by Region (2025)</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col">Q1</th>
<th scope="col">Q2</th>
<th scope="col">Q3</th>
<th scope="col">Q4</th>
</tr>
</thead>
<tbody>
<!-- Table data rows -->
</tbody>
<tfoot>
<tr>
<th scope="row">Total</th>
<td>$125,000</td>
<td>$148,000</td>
<td>$162,000</td>
<td>$175,000</td>
</tr>
</tfoot>
</table>
These section elements provide several accessibility benefits:
- They add semantic meaning to different parts of the table
- Screen readers can announce the table section (header, body, footer)
- They help with printing large tables (headers can repeat on each page)
- They provide logical grouping for styling and JavaScript manipulation
Table Headers: <th> vs <td>
Using <th> elements for headers (instead of styled <td> cells) is crucial for accessibility:
Inaccessible Approach ❌
<tr>
<td><strong>Name</strong></td>
<td><strong>Email</strong></td>
<td><strong>Phone</strong></td>
</tr>
Accessible Approach ✅
<tr>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Phone</th>
</tr>
While both examples might look similar visually (especially with CSS styling), the second example provides proper semantic meaning. Screen readers will announce the cells as headers and can associate them with their corresponding data cells.
The Role of Summaries
The summary attribute was used in HTML4 to provide additional context about a table's organization and purpose. In HTML5, this attribute is obsolete, but the concept is still important.
Instead of the summary attribute, use one of these techniques:
- Include detailed information in the
<caption> - Add descriptive text immediately before or after the table
- Use ARIA attributes (discussed later)
<table>
<caption>Quarterly Sales by Region (2025)</caption>
<!-- Table content -->
</table>
<p class="table-description">This table shows sales figures in thousands of dollars for our four regions across each quarter of 2025. The North region consistently shows the highest performance, while the West region shows the most growth year-over-year.</p>
Header Association Techniques
For tables to be truly accessible, each data cell must be programmatically associated with its corresponding headers. This association helps screen reader users understand what each piece of data represents.
The scope Attribute
The scope attribute explicitly tells assistive technologies which data cells a header cell relates to:
<table>
<tr>
<th scope="col">Name</th>
<th scope="col">Age</th>
<th scope="col">Location</th>
</tr>
<tr>
<td>Alice Smith</td>
<td>32</td>
<td>Seattle</td>
</tr>
</table>
In this example, each <th> element has a scope="col" attribute, indicating that it's a header for all cells in its column. This allows screen readers to announce "Name: Alice Smith" when focusing on that cell.
For row headers, use scope="row":
<table>
<tr>
<th scope="row">Age</th>
<td>32</td>
</tr>
<tr>
<th scope="row">Location</th>
<td>Seattle</td>
</tr>
</table>
The scope attribute can also take values of rowgroup or colgroup for more complex tables.
The id and headers Attributes
For more complex tables, especially those with irregular structures or multiple header levels, the id and headers attributes provide an explicit association between headers and data cells:
<table>
<caption>Quarterly Sales by Region</caption>
<tr>
<th id="empty"></th>
<th id="q1">Q1</th>
<th id="q2">Q2</th>
</tr>
<tr>
<th id="north">North</th>
<td headers="north q1">$50,000</td>
<td headers="north q2">$60,000</td>
</tr>
<tr>
<th id="south">South</th>
<td headers="south q1">$42,000</td>
<td headers="south q2">$43,000</td>
</tr>
</table>
In this example:
- Each header cell has a unique
idattribute - Each data cell has a
headersattribute that lists the IDs of all headers that apply to it - The
headersattribute can reference multiple IDs (space-separated)
When a screen reader encounters a cell with headers="north q1", it can announce "North, Q1: $50,000", providing complete context for the data.
When to Use scope vs. id/headers
Both techniques achieve the same goal but are suited to different scenarios:
- Use
scopewhen:- Your table has a simple structure with clear row/column headers
- Headers apply to entire rows or columns
- You need a simpler, more maintainable approach
- Use
id/headerswhen:- Your table has a complex or irregular structure
- Data cells relate to multiple headers that aren't in the same row/column
- You have nested or hierarchical headers
- You need precise control over header associations
ARIA Enhancements for Tables
Accessible Rich Internet Applications (ARIA) attributes can further enhance table accessibility, especially for complex or dynamic tables.
Table Roles
While HTML tables already have implicit ARIA roles, you can explicitly set roles for clarity:
<table role="table">
<caption>Monthly Budget</caption>
<tr role="row">
<th role="columnheader" scope="col">Category</th>
<th role="columnheader" scope="col">Amount</th>
</tr>
<tr role="row">
<th role="rowheader" scope="row">Rent</th>
<td role="cell">$1,200</td>
</tr>
</table>
Note: These ARIA roles are redundant with proper HTML elements, but they can be useful in cases where you need to create table-like structures with non-table elements (though this approach should be avoided when possible).
aria-labelledby and aria-describedby
These attributes can connect tables to external descriptions:
<h2 id="budget-title">Monthly Household Budget</h2>
<p id="budget-desc">This table shows our monthly household budget with actual spending compared to planned amounts.</p>
<table aria-labelledby="budget-title" aria-describedby="budget-desc">
<!-- Table content -->
</table>
When a screen reader encounters this table, it will announce the heading as the table's name and the paragraph as its description.
Sorting and Interaction Information
For interactive tables with sorting or filtering capabilities, ARIA attributes can convey the current state:
<table>
<tr>
<th aria-sort="ascending">Name</th>
<th aria-sort="none">Email</th>
<th aria-sort="none">Phone</th>
</tr>
<!-- Table content -->
</table>
For interactive header cells:
<th role="columnheader" aria-sort="none">
<button aria-label="Sort by name" onclick="sortTable()">Name</button>
</th>
Dynamic Table Updates
For tables that update dynamically (e.g., with live data), consider these ARIA attributes:
aria-live: Tells screen readers to announce updates to the tablearia-atomic: Determines whether the entire table or just changes are announcedaria-busy: Indicates the table is being updated
<table aria-live="polite" aria-atomic="false">
<!-- Table content -->
</table>
Best Practice: When using dynamic updates, avoid frequent changes that could overwhelm screen reader users, and ensure changes are properly announced.
Responsive Tables and Accessibility
Responsive design presents unique challenges for tables, especially on small screens. Here are techniques to maintain accessibility while making tables responsive:
Horizontal Scrolling
The simplest approach is to allow horizontal scrolling for tables that are too wide:
.table-container {
width: 100%;
overflow-x: auto;
border: 1px solid #ddd;
}
/* Ensure visible scrollbar for accessibility */
.table-container::-webkit-scrollbar {
height: 12px;
}
.table-container::-webkit-scrollbar-thumb {
background-color: #888;
border-radius: 6px;
}
Accessibility considerations for this approach:
- Ensure scrollbars are visible and usable
- Consider "sticky" headers that remain visible while scrolling
- Add visual indicators that content can be scrolled
- Test keyboard scrolling
Responsive Table Transformations
For better usability on small screens, tables can be transformed to a more mobile-friendly format:
@media (max-width: 768px) {
table, thead, tbody, th, td, tr {
display: block;
}
thead tr {
position: absolute;
top: -9999px;
left: -9999px;
}
tr {
border: 1px solid #ccc;
margin-bottom: 10px;
}
td {
border: none;
position: relative;
padding-left: 50%;
}
td:before {
position: absolute;
left: 6px;
width: 45%;
white-space: nowrap;
font-weight: bold;
}
/* Add content for each cell using data attributes */
td:nth-of-type(1):before { content: attr(data-label); }
td:nth-of-type(2):before { content: attr(data-label); }
td:nth-of-type(3):before { content: attr(data-label); }
/* Add more as needed */
}
The HTML needs to include data-label attributes on each cell:
<tr>
<td data-label="Name">Alice Smith</td>
<td data-label="Age">32</td>
<td data-label="Location">Seattle</td>
</tr>
This approach transforms each row into a card-like format on small screens, with each cell displaying its header label.
Table Alternatives
Sometimes the best solution is to provide an alternative to a complex table on small screens:
<div class="table-alternative">
<div class="card">
<h3>Alice Smith</h3>
<p><strong>Age:</strong> 32</p>
<p><strong>Location:</strong> Seattle</p>
</div>
<div class="card">
<h3>Bob Johnson</h3>
<p><strong>Age:</strong> 45</p>
<p><strong>Location:</strong> Portland</p>
</div>
</div>
<table class="desktop-only">
<!-- Original table content -->
</table>
Caution: When providing alternative views, ensure both versions contain the same information and are accessible.
Accessible Responsive Tables Checklist
- Maintain header-data associations in all view modes
- Ensure all content is available regardless of screen size
- Provide clear focus states that work at all screen sizes
- Test keyboard navigation and screen reader output in responsive views
- Consider adding skip links to bypass large tables on small screens
- Document any special interactions needed for mobile users
Testing Table Accessibility
To ensure your tables are truly accessible, regular testing is essential. Here are methods and tools to test table accessibility:
Screen Reader Testing
Testing with actual screen readers provides the most accurate feedback on how your tables will be experienced by users with visual impairments:
- NVDA or JAWS (Windows): Test how the table is announced and navigated
- VoiceOver (macOS/iOS): Check table navigation using VO keys and arrow keys
- TalkBack (Android): Test table accessibility on mobile devices
When testing with screen readers, verify that:
- The table is announced as a table with the correct number of rows and columns
- The caption or table description is announced
- Headers are properly associated with data cells
- Row and column navigation works as expected
- Cell content is announced clearly and in context
Keyboard Testing
Verify that all table functionality works with keyboard only:
- Navigate through all cells using the Tab key
- Test arrow key navigation in table cells (where supported)
- Ensure all interactive elements within cells are focusable and operable
- Verify that focus is always visible
- Test that fixed headers remain accessible when scrolling
Automated Testing Tools
While not comprehensive, automated tools can catch many common accessibility issues:
- WAVE (Web Accessibility Evaluation Tool): Checks for proper table structure
- axe DevTools: Tests for missing headers, associations, and other table issues
- Lighthouse: Includes table accessibility in its accessibility audit
- HTML validators: Catch structural errors in table markup
Manual Inspection Checklist
In addition to automated testing, manually inspect tables for these common issues:
- Verify that all
<th>elements havescopeattributes or are referenced byheadersattributes - Check that tables have appropriate captions or descriptions
- Ensure visual formatting (borders, backgrounds) has sufficient contrast
- Verify that table content makes sense when read linearly (screen reader mode)
- Confirm that data-cell relationships are clear without relying solely on visual layout
- Test at different screen sizes to ensure responsive behavior maintains accessibility
User Testing
Whenever possible, include users with disabilities in your testing:
- Recruit screen reader users to navigate your tables
- Include keyboard-only users in testing
- Test with users who have low vision or color vision deficiencies
- Gather feedback on usability, not just technical accessibility
Practical Examples of Accessible Tables
Let's look at some practical examples of accessible tables for common scenarios:
Example 1: Simple Data Table
<table>
<caption>Employee Information</caption>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Department</th>
<th scope="col">Email</th>
<th scope="col">Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice Smith</td>
<td>Marketing</td>
<td>alice@example.com</td>
<td>555-1234</td>
</tr>
<tr>
<td>Bob Johnson</td>
<td>Finance</td>
<td>bob@example.com</td>
<td>555-2345</td>
</tr>
</tbody>
</table>
Example 2: Complex Table with Row and Column Headers
<table>
<caption>Quarterly Sales by Region (in thousands of dollars)</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col">Q1</th>
<th scope="col">Q2</th>
<th scope="col">Q3</th>
<th scope="col">Q4</th>
<th scope="col">Total</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">North</th>
<td>50</td>
<td>60</td>
<td>70</td>
<td>80</td>
<td>260</td>
</tr>
<tr>
<th scope="row">South</th>
<td>40</td>
<td>40</td>
<td>45</td>
<td>45</td>
<td>170</td>
</tr>
</tbody>
<tfoot>
<tr>
<th scope="row">Total</th>
<td>90</td>
<td>100</td>
<td>115</td>
<td>125</td>
<td>430</td>
</tr>
</tfoot>
</table>
Example 3: Table with Irregular Structure Using id/headers
<table>
<caption>Product Comparison by Feature</caption>
<thead>
<tr>
<th id="feature">Feature</th>
<th id="basic">Basic Model</th>
<th id="premium">Premium Model</th>
<th id="pro">Pro Model</th>
</tr>
</thead>
<tbody>
<tr>
<th id="price" headers="feature">Price</th>
<td headers="basic price">$299</td>
<td headers="premium price">$499</td>
<td headers="pro price">$799</td>
</tr>
<tr>
<th id="warranty" headers="feature">Warranty</th>
<td headers="basic warranty">1 year</td>
<td colspan="2" headers="premium pro warranty">2 years</td>
</tr>
<tr>
<th id="support" headers="feature">Support</th>
<td headers="basic support">Email only</td>
<td headers="premium support">Email and phone</td>
<td headers="pro support">24/7 dedicated</td>
</tr>
</tbody>
</table>
Example 4: Responsive Table with Data Attributes
<!-- CSS for responsive table -->
<style>
@media (max-width: 768px) {
table, thead, tbody, th, td, tr {
display: block;
}
thead tr {
position: absolute;
top: -9999px;
left: -9999px;
}
tr {
border: 1px solid #ccc;
margin-bottom: 10px;
}
td {
border: none;
position: relative;
padding-left: 50%;
min-height: 30px;
}
td:before {
position: absolute;
left: 6px;
width: 45%;
padding-right: 10px;
white-space: nowrap;
content: attr(data-label);
font-weight: bold;
}
}
</style>
<!-- HTML for responsive table -->
<table>
<caption>Employee Information</caption>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Department</th>
<th scope="col">Email</th>
<th scope="col">Phone</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Name">Alice Smith</td>
<td data-label="Department">Marketing</td>
<td data-label="Email">alice@example.com</td>
<td data-label="Phone">555-1234</td>
</tr>
<tr>
<td data-label="Name">Bob Johnson</td>
<td data-label="Department">Finance</td>
<td data-label="Email">bob@example.com</td>
<td data-label="Phone">555-2345</td>
</tr>
</tbody>
</table>
Practical Exercise: Making an Accessible Table
Let's apply what we've learned by taking an inaccessible table and making it fully accessible.
Starting with an Inaccessible Table
<table border="1">
<tr bgcolor="#cccccc">
<td><b>Product</b></td>
<td><b>Price</b></td>
<td><b>In Stock</b></td>
<td><b>Features</b></td>
</tr>
<tr>
<td>Basic Widget</td>
<td>$19.99</td>
<td>Yes</td>
<td>
<li>Durable</li>
<li>Easy to use</li>
</td>
</tr>
<tr>
<td>Advanced Widget</td>
<td>$29.99</td>
<td>Limited</td>
<td>
<li>Durable</li>
<li>Easy to use</li>
<li>Advanced features</li>
</td>
</tr>
<tr>
<td>Premium Widget</td>
<td>$49.99</td>
<td>No</td>
<td>
<li>Durable</li>
<li>Easy to use</li>
<li>Advanced features</li>
<li>Premium support</li>
</td>
</tr>
</table>
Step 1: Add Semantic Structure
<table>
<caption>Product Comparison</caption>
<thead>
<tr>
<th scope="col">Product</th>
<th scope="col">Price</th>
<th scope="col">In Stock</th>
<th scope="col">Features</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Basic Widget</th>
<td>$19.99</td>
<td>Yes</td>
<td>
<ul>
<li>Durable</li>
<li>Easy to use</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">Advanced Widget</th>
<td>$29.99</td>
<td>Limited</td>
<td>
<ul>
<li>Durable</li>
<li>Easy to use</li>
<li>Advanced features</li>
</ul>
</td>
</tr>
<tr>
<th scope="row">Premium Widget</th>
<td>$49.99</td>
<td>No</td>
<td>
<ul>
<li>Durable</li>
<li>Easy to use</li>
<li>Advanced features</li>
<li>Premium support</li>
</ul>
</td>
</tr>
</tbody>
</table>
Step 2: Add Responsive Styling and Accessibility
<!-- Add this to the head section -->
<style>
/* Base table styles */
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
caption {
font-weight: bold;
font-size: 1.2em;
padding: 10px;
text-align: left;
}
th, td {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
/* Ensure lists within cells are properly styled */
td ul {
margin: 0;
padding-left: 20px;
}
/* Focus styles for keyboard navigation */
th:focus, td:focus {
outline: 2px solid #4a90e2;
outline-offset: -2px;
}
/* Responsive styles */
@media (max-width: 768px) {
table, thead, tbody, th, td, tr {
display: block;
}
thead tr {
position: absolute;
top: -9999px;
left: -9999px;
}
tr {
border: 1px solid #ddd;
margin-bottom: 15px;
}
td, tbody th {
border: none;
border-bottom: 1px solid #ddd;
position: relative;
padding-left: 50%;
min-height: 30px;
}
td:before, tbody th:before {
position: absolute;
top: 12px;
left: 12px;
width: 45%;
padding-right: 10px;
white-space: nowrap;
content: attr(data-label);
font-weight: bold;
}
/* Special handling for the features cell */
td:last-child {
padding-left: 12px;
padding-top: 40px;
}
td:last-child:before {
top: 12px;
left: 12px;
}
}
</style>
<!-- Updated table with data-label attributes -->
<div class="table-container">
<table>
<caption>Product Comparison - Widget Series</caption>
<thead>
<tr>
<th scope="col">Product</th>
<th scope="col">Price</th>
<th scope="col">In Stock</th>
<th scope="col">Features</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" data-label="Product">Basic Widget</th>
<td data-label="Price">$19.99</td>
<td data-label="In Stock">Yes</td>
<td data-label="Features">
<ul>
<li>Durable</li>
<li>Easy to use</li>
</ul>
</td>
</tr>
<tr>
<th scope="row" data-label="Product">Advanced Widget</th>
<td data-label="Price">$29.99</td>
<td data-label="In Stock">Limited</td>
<td data-label="Features">
<ul>
<li>Durable</li>
<li>Easy to use</li>
<li>Advanced features</li>
</ul>
</td>
</tr>
<tr>
<th scope="row" data-label="Product">Premium Widget</th>
<td data-label="Price">$49.99</td>
<td data-label="In Stock">No</td>
<td data-label="Features">
<ul>
<li>Durable</li>
<li>Easy to use</li>
<li>Advanced features</li>
<li>Premium support</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Additional context for screen readers -->
<p id="table-description">This table compares three widget models, showing price, availability, and key features for each. The Premium Widget offers the most features but is currently out of stock.</p>
This exercise demonstrates how to transform an inaccessible table into one that follows accessibility best practices, including:
- Proper semantic structure with
<thead>,<tbody>, and<caption> - Appropriate
<th>elements withscopeattributes - Responsive design that works on mobile devices
- Proper nesting of list elements
- Focus styles for keyboard navigation
- Additional descriptive text for context
Summary and Key Takeaways
In this lecture, we've explored the essential aspects of table accessibility:
- Semantic Structure: Using proper table elements like
<caption>,<thead>,<tbody>, and<tfoot>provides important context to assistive technologies - Header Association: The
scopeattribute orid/headersattributes ensure data cells are properly associated with their headers - ARIA Enhancements: Additional ARIA attributes can provide even more context and improve interactions for complex tables
- Keyboard Navigation: Ensuring tables are fully navigable using the keyboard is essential for accessibility
- Responsive Accessibility: Tables must remain accessible across all device sizes, which may require special techniques
- Testing: Regular testing with actual assistive technologies is crucial for ensuring true accessibility
Remember these key principles:
- Always use proper semantic structure for tables
- Ensure every data cell is associated with its headers
- Provide context through captions and descriptions
- Test with real assistive technologies
- Consider responsive behavior and mobile accessibility
- Focus on the user experience, not just technical compliance
By implementing these accessibility features, you'll create tables that are usable by everyone, regardless of their abilities or the technologies they use to access the web.
Homework Assignment
Your task is to create a fully accessible, responsive data table based on one of the following datasets (choose one):
- Comparative Product Information: Create a table comparing at least 5 products across at least 6 features
- Financial Data: Create a table showing financial performance across quarters and categories
- Schedule/Timetable: Create a weekly schedule or event timetable
- Nutritional Information: Create a table comparing nutritional data across multiple food items
- Sports Statistics: Create a league standings or player statistics table
Requirements:
- Use all semantic table elements (
<table>,<caption>,<thead>,<tbody>,<tfoot>, etc.) - Implement proper header associations using
scopeorid/headersattributes - Include at least one cell that spans multiple rows or columns
- Make the table responsive using one of the techniques discussed
- Style the table for visual clarity and readability
- Include focus styles for keyboard navigation
- Add appropriate ARIA attributes where helpful
- Include a description or summary of the table content
- Document your accessibility considerations in comments
Submission:
- Submit both HTML and CSS files
- Include a brief document describing your accessibility approach
- Note any challenges you encountered and how you solved them
- Describe how you tested the accessibility of your table
Be prepared to discuss your implementation and demonstrate your table's accessibility features in the next class.