DEV Community

Cover image for Creating responsive data tables with CSS
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

Creating responsive data tables with CSS

Written by Timonwa Akintokun✏️

Data tables are an important part of many websites and applications as they allow us to display complex data in a way that’s easy to reference, enabling us to see results quickly. We can also use data tables to organize and analyze data or compare data from different sources.

However, many data tables are designed for desktop use and are difficult to view and interact with on mobile devices. On smaller screens the cell content wraps, making it difficult to read and forcing the user to scroll or zoom in to see the data.

In this article, we’ll explore options for creating responsive data tables using CSS and techniques for making them accessible and easy to use on mobile devices.

Jump ahead:

What is a responsive data table?

A responsive data table is designed to work well on both desktop and mobile devices. When a user views a responsive data table on a mobile device, the data table will automatically adjust to fit the screen size, making it easy to view and interact with the data. And when the user views the same data table on a desktop device, the data table will automatically adjust to fit the screen size, making it easy to view and interact with the data.

Defining the structure

When creating a responsive data table, the first step is to properly define its structure. Having a correct structure will make the table easier to style and maintain and will also help ensure it is accessible and has a semantic structure.

A typical HTML data table consists of the following elements:

  • <table>: used to define the data table; it contains the <thead>, <tbody>, and <tfoot> elements
  • <thead>: used to define the header of the data table; it contains the <tr> element, which contains the <th> elements
  • <tbody>: used to define the body of the data table; it contains the <tr> elements, which contain the <td> elements
  • <tfoot>: used to define the footer of the data table; it contains the <tr> element, which contains the <td> elements

In practice, a basic HTML data table will look like this:

<table>
  <thead>
    <tr>
      <th>Column 1</th>
      <th>Column 2</th>
      <th>Column 3</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Row 1, Column 1</td>
      <td>Row 1, Column 2</td>
      <td>Row 1, Column 3</td>
    </tr>
    <tr>
      <td>Row 2, Column 1</td>
      <td>Row 2, Column 2</td>
      <td>Row 2, Column 3</td>
    </tr>
    <tr>
      <td>Row 3, Column 1</td>
      <td>Row 3, Column 2</td>
      <td>Row 3, Column 3</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td>Footer 1</td>
      <td>Footer 2</td>
      <td>Footer 3</td>
    </tr>
  </tfoot>
</table>
Enter fullscreen mode Exit fullscreen mode

By organizing the data table into the appropriate HTML elements, we can lay a solid foundation for applying CSS styles and implementing responsive design techniques. This structured approach makes it easier to manage the data table's content, enhance its functionality, and optimize its display across different devices and screen sizes.

Adding styling

Without any styling, our HTML example table will look like this: HTML Table No Styling The browser will automatically add some default styling to the table, but not enough to make the table look good! Fortunately, we can improve the table’s appearance with some basic CSS:

  *,
  *::before,
  *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  body {
    padding: 20px;
  }
  table {
    border-collapse: collapse;
  }
  th,
  td {
    padding: 8px;
    text-align: left;
    border: 1px solid #ddd;
  }
  tbody tr:hover {
    background-color: #f5f5f5;
  }
  th {
    background-color: #4caf50;
    color: white;
  }
  tfoot {
    background-color: #4a524a;
    color: white;
  }
Enter fullscreen mode Exit fullscreen mode

Simple Table With Styling Even on the smallest of screens, this basic table with simple styling will display the data in a way that is easy to read and understand. But when we start to add more data and more rows, it begins to look cluttered and becomes difficult to read: Table Mobile Screen Text Wrapping This is where the need for responsive design comes in.

Considering use cases

When designing a responsive data table, it's important to consider the different screen sizes and devices that the table will be viewed on. This will help us determine the best way to display the data and ensure that the table is easy to read and understand on all devices.

Here's an example of a table containing employee data. The table is not responsive, and the data in the cells are not aligned properly. When the screen size becomes smaller than the table's width, the data in the cells will start to wrap, making it difficult to read: Complex Table Cell Wrapping To make the table responsive, we need to write some CSS. Let’s look at some responsive data table techniques.

Controlling table width and overflow

Controlling the width of the table is one of the most important things we can do to make it responsive. This ensures that the table doesn't distort the layout of the page.

By wrapping the table in a <div> element and setting the width of the <div> element to 100% or the maximum width required, we can make the table scrollable when the screen size or table wrapper becomes smaller than the table's width, thus preventing the table from distorting the layout of the page:

<style>
  .table-wrapper {
    width: 100%;
    /* max-width: 500px; */
    overflow-x: auto;
  }
</style>
<body>
  <div class="table-wrapper">
    <table> ... </table>
  </div>
</body>
Enter fullscreen mode Exit fullscreen mode

Adjusting column width and text display

By default, when a table is displayed in the browser, it tries to fit the table within the screen size or the width of its container. This can result in columns being resized and the content of cells wrapping into multiple lines. The browser breaks the content at word spaces, and if there is no more space, the table will start scrolling horizontally.

This wrapping of content can lead to rows having varying heights, making the table appear messy and challenging to read. Additionally, since column widths depend on the width of their largest cells, the columns may have different widths, further contributing to the untidy appearance of the table and making it difficult to read.

There are multiple approaches to address this issue depending on the desired data display, let’s look at a few.

Using CSS min-width and max-width

We can adjust the column widths based on the maximum content length, preventing content wrapping and ensuring that all columns have consistent widths. This approach is useful when you don't want the content to wrap, but it is not always practical since the maximum content length may be unknown or hard to determine.

Also, it can be challenging to set column widths manually. Another tricky scenario is when one column needs to accommodate a single cell with extensive content while others have minimal content. This can result in excessively wide columns and an untidy appearance:

td:first-child {
  min-width: 850px;
  max-width: 850px;
}
Enter fullscreen mode Exit fullscreen mode

Table Different Column Widths Here we’ve used the CSS min-width and max-width properties to set the first column to have a minimum and maximum width of 850px. This ensures that the column will always be 850px wide, regardless of the content.

This approach works best for scenarios in which you have fairly consistent data lengths.

Using fixed column width

Another approach is to assign fixed widths to the columns while allowing the content to wrap within them. With this approach, columns will have consistent widths, but the table may still have an untidy appearance as the wrapped content can result in rows of different heights:

table {
  width: 800px;
}
th,
td {
  width: calc(800px / 3);
}
Enter fullscreen mode Exit fullscreen mode

Table Consistent Column Widths Different Row Heights Here we’ve set the table to have a width of 800px and the columns to have a width of 800px divided by the number of columns, which is 3 in this case. This ensures that the columns will always be the same width, regardless of the content. This approach works well for scenarios where visual integrity is a priority and it’s acceptable to vary row heights.

Truncating cell content

A third approach is to truncate or slice the content of the cells to ensure consistent row and column widths and heights. By limiting the content's display length, we can maintain uniformity within the table.

This technique is especially useful when dealing with long text or large amounts of data. However, it's important to consider the context and purpose of the table.

In some cases, truncating or slicing cell content may compromise readability or result in the loss of important information. It's crucial to evaluate the specific requirements and priorities of the data being presented before deciding whether to slice the content.

Here’s an example of a data table with truncated cells:

th,
td {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
td:first-child {
  min-width: 200px;
  max-width: 200px;
}
Enter fullscreen mode Exit fullscreen mode

Table Truncated Cell Content Here we’ve set the first column to have a minimum and maximum width of 200px. This ensures that the column will always be 200px wide, regardless of the content. We’ve also set the white-space property to nowrap to prevent the content from wrapping and the overflow property to hidden to hide any content that overflows the cell. Finally, We’ve set the text-overflow property to ellipsis to add an ellipsis to the end of the content that overflows the cell. This approach works best for scenarios where it’s critical to maintain consistent row and column dimensions.

Handling long links or words with word-break

On some occasions, we may encounter tables containing long links or words that can cause the table to overflow and disrupt the layout. This can be problematic as it can make the table difficult to read and interpret. To address this issue, we can use the word-break property to break long words and links and prevent them from disrupting the table's layout.

Here’s an example:

<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th>Column 1</th>
        <th>Column 2 with long links/words</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Row 1, Column 1</td>
        <td>https://averylonglink.com/scdnddsffrffjfsjfdfdfdcndfdjfkfdf33rcfrerrfdfcrerecfewreceewrwercrerecrererereerererergrtcghvtvhtrvfgf</td>
      </tr>
      <tr>
        <td>Row 2, Column 1</td>
        <td>Honorificabilitudinitatibus califragilisticexpialidocious Taumatawhakatangihangakoauauotamateaturipukakapikimaungahoronukupokaiwhenuakitanatahu</td>
      </tr>
      <!-- Add more rows as needed -->
    </tbody>
  </table>
</div>
Enter fullscreen mode Exit fullscreen mode
.table-wrapper {
  width: 100%;
  max-width: 500px;
  overflow-x: auto;
}
th,
td {
  padding: 8px;
  text-align: left;
  border: 1px solid #ddd;
}
td:first-child {
  min-width: 150px;
  max-width: 150px;
}
td:last-child {
  word-break: break-all;
}
Enter fullscreen mode Exit fullscreen mode

In the code above, if we comment out the word-break and overflow CSS properties to prevent them from being applied to the table, the contents of the second column stretch the width of the table past the intended maximum width of 500px: Column Extending Past Max Table Width By applying the word-break and overflow CSS properties to the table, we see that the table now retains our desired width. And at the same time, the long content is broken into multiple lines, making it easier to read and interpret: Table CSS Overflow Word-Break

Adjusting CSS properties with media queries

Media queries enable us to apply conditions to how CSS properties appear, based on the screen size or device that the page is being viewed on. This allows us to create a responsive design that will look good on all devices. Here are some of the CSS properties that we can adjust with media queries:

  • Font size: can be modified to ensure that the text within the table is legible on smaller screens without overcrowding the layout; decreasing font size can help maintain readability while accommodating limited screen space
  • Column widths: can be adjusted to control the amount of space each column occupies. For smaller screens, column widths may be reduced to prevent horizontal scrolling or to allow the table to fit within the available screen width
  • Padding and margins: may be altered to create spacing and visual separation between different parts of the table to enhance readability and improve the overall aesthetic appeal of the table on various devices
  • Alignment and text formatting: alignment properties, such as text-align, can be modified to ensure that the content within the table is properly aligned based on the screen size. Additionally, text formatting properties, such as text-overflow and white-space, may be adjusted to control how text wraps or truncates within table cells on smaller screens
  • Display and visibility: can be modified to adjust the visibility of certain table elements or even entire columns based on screen size; this enables us to hide enabling non-essential information or elements that could clutter the table on smaller screens

These are just a few examples of the CSS properties that can be adjusted with media queries to create responsive tables. The specific properties you choose to modify will depend on your table's design, content, and the desired user experience on different devices.

How do you make a responsive data table accessible?

Accessibility is an essential aspect of web design. It ensures that people with disabilities can access and use websites and web applications. It also helps improve the user experience for everyone, including those without disabilities.

Data tables are often used to display large amounts of information. This can make it difficult for people with disabilities to navigate the table and find the information they need. Accessibility is especially important for data tables because they often contain large amounts of information that can be difficult to navigate without proper accessibility features.

It may be helpful to test your data table with a screen reader, such as AWS, NVDA, and VoiceOver. Using this type of assistive technology to the table’s content and structure will help you identify any potential issues and ensure that the table is properly interpreted and navigable by individuals with visual disabilities.

It’s also a good idea to test your data table with keyboard navigation. Individuals with motor disabilities may have difficulty using a mouse or other pointing device and may need to rely on keyboard navigation to move through a data table.

There are several ways to make data tables accessible; let’s take a look.

Using semantic HTML

Semantic HTML is a way of writing HTML that makes it easier for people with disabilities to understand the content. It also makes it easier for search engines to understand the content. Semantic HTML is important for data tables because it makes it easier for people with disabilities to understand the table.

Here are some semantic HTML elements that can be used to make data tables accessible:

  • <table>: used to define a table; it can be used to make data tables accessible by providing a structure for the table
  • <caption>: used to provide a caption for a table; it can be used to make data tables accessible by describing the table's purpose
  • <thead>: used to define the table's header; it can be used to make data tables accessible by providing a structure for the table's header
  • <tbody>: used to define the table's body; it can be used to make data tables accessible by providing a structure for the table's body
  • <tfoot>: used to define the table's footer; it can be used to make data tables accessible by providing a structure for the table's footer
  • <tr>: used to define a row in a table; it can be used to make data tables accessible by providing a structure for the table's rows
  • <th>: used to define a header cell in a table; it can be used to make data tables accessible by providing a structure for the table's header cells
  • <td>: used to define a data cell in a table; it can be used to make data tables accessible by providing a structure for the table's data cells

Here’s an example of a data table with semantic HTML:

<table>
  <caption>Employee Information</caption>
  <thead>
    <tr>
      <th scope="col">ID</th>
      <th scope="col">Name</th>
      <th scope="col">Position</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>001</td>
      <td>John Smith</td>
      <td>Manager</td>
    </tr>
    <tr>
      <td>002</td>
      <td>Jane Doe</td>
      <td>Developer</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td colspan="3">Total employees: 2</td>
    </tr>
  </tfoot>
</table>
Enter fullscreen mode Exit fullscreen mode

Using the scope attribute

The scope attribute is used to define the scope of the data table’s header cell, <th>. It helps assistive technologies, such as screen readers, understand the relationships between header cells and data cells in the table.

The scope attribute can have the following values:

  • row: indicates that the header cell applies to a row of data cells. It associates the header cell with the data cells in the same row
  • col: indicates that the header cell applies to a column of data cells. It associates the header cell with the data cells in the same column
  • rowgroup: indicates that the header cell applies to a group of rows
  • colgroup: indicates that the header cell applies to a group of columns

By using the scope attribute appropriately, screen readers can announce the headers when reading the table, providing context and improving the understanding of the table's structure. Here’s an example:

<table>
  <caption>Monthly Sales Report</caption>
  <thead>
    <tr>
      <th scope="col">Month</th>
      <th scope="col">Product A</th>
      <th scope="col">Product B</th>
      <th scope="col">Product C</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">January</th>
      <td>$1000</td>
      <td>$1500</td>
      <td>$1200</td>
    </tr>
    <tr>
      <th scope="row">February</th>
      <td>$900</td>
      <td>$1800</td>
      <td>$1100</td>
    </tr>
    <tr>
      <th scope="row">March</th>
      <td>$1200</td>
      <td>$1300</td>
      <td>$1000</td>
    </tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

Table Optimized Accessibility Scope Attribute The above table represents a monthly sales report with three products (A, B, and C) and their corresponding sales figures for each month. The scope attribute is used in the <th> elements to define the scope of the header cells. The scope="col" attribute is used for the header cells in the table header row <thead> indicating that each header cell applies to a column.

The scope="row" attribute is used for the header cells in the table body rows, <tbody>, indicating that each header cell applies to a row.

By using the scope attribute appropriately, assistive technologies can associate the header cells with their corresponding data cells, improving the accessibility and understanding of the table's structure for users with disabilities.

Using the summary attribute

The summary attribute is used to provide a summary of the table's purpose and structure. It also helps assistive technologies, such as screen readers, understand the table's purpose and structure. Here's an example of how the summary attribute can be used:

<table summary="Monthly sales report for products A, B, and C">
  <!-- table content goes here -->
</table>
Enter fullscreen mode Exit fullscreen mode

In the above code, the summary attribute is added to the <table> element, and its value is set to "Monthly sales report for products A, B, and C". When assistive technologies encounter a table with a summary attribute, they can read out the summary to provide users with an understanding of what the table contains and its purpose. This is especially valuable for users with visual impairments who rely on screen readers to navigate and comprehend web content. Including a meaningful and informative summary attribute is an important practice to enhance the accessibility of data tables, as it allows users to quickly grasp the table's purpose and context without having to analyze the entire content.

ARIA attributes

ARIA (Accessible Rich Internet Applications) attributes are used to enhance the accessibility of web content for users with disabilities. They provide additional information about the purpose and structure of web content, allowing assistive technologies to better understand and navigate the content. One commonly used ARIA attribute is the role attribute. This attribute specifies the semantic role of an element, helping assistive technologies understand its purpose. For data tables, the role attribute is typically set to "table" to indicate that the element represents a table. Here's an example of how the role attribute can be used with a table:

<table role="table">
  <thead role="rowgroup">
    <tr role="row">
      <th role="columnheader">Name</th>
      <th role="columnheader">Age</th>
    </tr>
  </thead>
  <tbody role="rowgroup">
    <tr role="row">
      <td role="cell">John</td>
      <td role="cell">25</td>
    </tr>
    <tr role="row">
      <td role="cell">Jane</td>
      <td role="cell">30</td>
    </tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

Here is another example of how the role attribute can be used with a table that doesn't use the semantic HTML elements:

<div role="table">
  <div role="rowgroup">
    <div role="row">
      <div role="columnheader">Name</div>
      <div role="columnheader">Age</div>
    </div>
    <div role="row">
      <div role="cell">John</div>
      <div role="cell">25</div>
    </div>
    <div role="row">
      <div role="cell">Jane</div>
      <div role="cell">30</div>
    </div>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Several other ARIA attributes be used to enhance the accessibility of data tables, such as the following:

  • aria-label: used to provide a label for an element. It can be used to provide a label for a table, row, column, or cell
  • aria-sort: used to indicate the default sorting order of a sortable column in the table. It can have values like "ascending", "descending", or "none"
  • aria-rowindex: used to indicate the row index of a row in the table
  • aria-labelledby: used to provide a label for an element using the id of another element. It can be used to provide a label for a table, row, column, or cell
  • aria-describedby: used to describe an element using the id of another element. It can be used to describe a table, row, column, or cell

There are several other ARIA attributes that can be used to enhance the accessibility of data tables. For more information, refer to the W3C ARIA specification.

Using color contrast

Color contrast is an important accessibility feature that ensures that text is readable against its background. It is especially useful for individuals with visual impairments who may have difficulty reading text that is not sufficiently contrasted. You can use a color contrast checker to test the accessibility of data tables. There are several color contrast checkers available, including WebAIM's color contrast checker.

Adding alt text to images

Alternative text (or alt text) is an important accessibility feature that provides a text alternative for images. It is especially useful for individuals with visual impairments who may have difficulty viewing images. By adding alternative text to images in data tables, we can help ensure that the table is properly interpreted and navigable by individuals using assistive technologies.

Conclusion

In this article, we discussed several strategies for optimizing data tables on smaller screens. Each approach has distinct use cases, and it's essential to consider your specific requirements before choosing one.

It’s also possible to combine multiple approaches within a single table by applying different approaches to specific columns or rows. This allows for a more tailored approach to handle specific content and achieve the desired display outcome.

For example, you might choose to set fixed widths for columns with shorter content, truncate or slice long text in certain columns, and use flexible widths for others. This flexibility allows for a customized solution that balances readability and visual consistency. Consider your data context, user experience goals, and tradeoffs involved to make an informed decision.

We also discussed how to make data tables accessible by using semantic HTML, the scope attribute, the summary attribute, ARIA attributes, screen readers, keyboard navigation, color contrast, and alternative text for images. By implementing these techniques, you can ensure that your responsive data tables are accessible and usable on smaller screens. You can view and play with all the code snippets on CodePen.


Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.

LogRocket Signup

LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web and mobile apps — Start monitoring for free.

Top comments (0)