3 Ways to Make Sticky Table Headers Work in Websites

Three ways to solve this problem which really shouldn’t be a problem in the first place

Ali Kamalizade
ITNEXT

--

A table
Photo by Markus Spiske on Unsplash

One disadvantage the web has compared to mobile platforms like Apple iOS and Android: without third-party libraries, developers only have rather basic UI controls to start with. While HTML5 provides a lot of semantic elements to express even complex layouts and respecting accessibility, the default UI controls haven’t kept up with time that well. Either it’s the style that looks outdated (though the Google Chrome and Microsoft Edge teams have started an initiative to improve the default UI controls) or the functionality is too limited by today’s standards.

Let’s take the<table> element as an example. Even if the default style is rather basic, a pure HTML5 table gets the job of displaying data in a tabular view done. However, it lacks functionality and usability that one might expect in a modern application:

  • You can’t easily sort by a column in a <table>
  • <table> doesn’t provide a way to filter a table (e.g. with a full-text search)
  • <table> doesn’t provide techniques like infinite scroll or virtual scroll to improve the performance if there are many rows
  • There’s no easy way to have the header of a <table> to be sticky

The last point in particular is quite important. If you need to display hundreds or thousands of records in a table with many columns, the table columns help the user to make understand the content of the table. For example: think of a users table in a company with thousands of employees. Such a big table quickly becomes hard to read without seeing the table columns.

One image is not like the other :)

We’re sending people to the moon so we should be able to make sticky table headers work in our static websites and web applications without much effort, right? Let’s have a look at some ways we can achieve this:

  • Use a UI component library which provides a table component
  • Use CSS to achieve sticky table headers
  • Don’t use a table in the first place

Use a UI component library which includes a table component

Modern UIs are composed of multiple components. Hence, many projects use UI libraries like Bootstrap or Angular Material. If you are using a component library which already provides a table component, you may be in luck! Many UI libraries include styles and extended functionality for tables. If your UI library of choice supports sticky table headers then it’s often simply a matter of applying a specific CSS class or a specific HTML attribute to achieve this.

The following screenshot is showing a table component from Angular Material with a sticky header.

However, it doesn’t make too much sense to use a UI library only for a single UI component. Therefore, you should include a UI library if you use more of it than a table component.

Use CSS to achieve sticky table headers

Even if CSS can be weird sometimes, CSS can do a lot so can we make sticky table headers using CSS? Yes, but it depends. In some browsers, you can use position: sticky to make any element sticky. Sadly, it’s not as easy to just apply this on the <tr> element as one might expect. To make it work for as many browsers as possible, you currently need to apply this to the <th> elements. Furthermore, the wrapper element around <table> needs to have a explicit height or max-height set.

The example below shows a simple table with fixed table column headers.

A scrollable table with fixed table headers
A scrollable table with fixed table headers

This approach requires no third-party dependencies or JavaScript which is nice. If you are targeting mostly modern browsers this way will probably be fine. However, if you need to support older browsers like IE11 then you need another solution. Keep in mind that while browser support for position: sticky is rather good in theory you may run into unexpected issues so don’t forget to do some testing in different browsers.

Don’t use a <table> in the first place

This seems like a obvious advice. After all, if a <table> doesn’t cut it then who’s gonna stop you from using something else. You can use Flexbox or CSS Grid to create a table-like layout. A sample implementation using bulma.css could look like this:

A table-like grid using bulma.css
A table-like grid without using a <table> element

The code mentioned above is fairly easy to explain:

  • A static container for displaying the “table headers”
  • A container with an explicit max-height for displaying the table contents. Since the container can’t exceed a specific height the content below and above the “table content” should always be visible.
  • A static container for everything below the “table” like action buttons

However, this code is not very accessible and semantic. It’s a lot of <div> elements which a screenreader can not easily interpret (to my knowledge). Even a developer would not be able to tell how many rows this “table” contains if the CSS class of the “table cells” would not give it away.

If you want to go this route then I advise you to ensure accessibility by setting correct ARIA attributes. This is an aspect where a native <table> fares far better as native elements have rather good built-in accessibility. MDN recommends developers to prefer using the correct semantic HTML element over using ARIA, if such an element exists.

Conclusion

Thanks for reading this short post about ways to create tables with sticky headers. As almost always there is not a single solution that will work for every use case. As a developer you have to decide which approach works best for your case. Do you know a better way to make sticky table headers in web? Let me know in the comments.

--

--

Co-founder of Sunhat. Posts about software engineering, startups and anything else. 有難うございます。🚀