Ultimate guide to table UI patterns
Many agree that tables are a phenomenon in user interface design: they are very important parts of user interfaces but often overlooked. Tables show structured data and their purpose is to make that data readable, scannable and easily comparable. The thing is that in many cases tabular data is obscured. This is why tables have bad reputation and many find them boring.
The truth is that the are everything but boring. For people who need tables in everyday work they are hated element that makes them scream. And it shouldn’t be this way. Here are some of the patterns that can help in creating less evil tables.
Alternating rows styling
Ok, this one is pretty obvious. But is it? Take a look at the web applications (and websites) today and you will see that many don’t apply it. So it is not obvious and that’s why it’s first in the list here.
By styling alternating rows differently you increase the ability of users to distinguish between overcrowded data in multiple rows and columns. You can use background color or background image. If background color is used it should be just slightly lighter/darker than a page background. For background images you should choose subtle gradients that match your color scheme. You can also combine background colors/images with table borders. Table header and footer should be easily recognizable and to achieve that you can use darker (or lighter) colors than table row colors.
BlinkCampaign uses subtle green color for alternate rows while keeping the header a bit darker.
Full row selection
If there is a single action that can be performed on a specific row, you can make the entire row clickable. This expands clickable area and declutters an interface. This can be used if, for instance, the only action you can perform on each row is view details. Each row should have hover state styled differently. There are several ways to achieve this effect, among which I would recommend you RowSelect jQuery plugin.
CrazyEgg uses full row selection to expand the details of the current selection (we’ll talk about this pattern a bit later). Row which is being hovered is slightly lighter. I really like how they designed this area (as well as the rest of the application).
When you need to group related rows you can consider using table sections (or table grouping). A section is a part of the table that groups related data. All groups shares same set of columns. For example, in a table that shows list of countries, regions are natural way to group rows. Each section should be styled differently and can be collapsible/expandable. Under each section you can show summarized data, if needed.
PulseApp uses table sections to show income and expenses details, but also to group data in subsections that will show even more details. Each section and subsection is expandable.
Sorting is used for cases when users have difficulties in finding a row they want in a very large set of data but they don’t know any keyword that can be searched by. Users also sort tables by columns when they want to compare adjacent information.
The common practice for enabling sorting on tables is to make header labels clickable. A column by which the table is sorted should be marked. This is usually done by placing an arrow next to column name, indicating in which order the column is sorted (ascending or descending). Clicking on a column that is already sorted should just reverse the order.
There has to be a clear difference between sortable columns and the others that aren’t. It is a good practice to sort table by default by one of the key columns.
Quite usable plugin is TableSorter which is very simple to use. It sorts many known data types and you can define your own as well. It also supports multi-column sorting, but I a not big fan of it anyway.
OneHub application clearly marks the sorted column and sorting order. What I like about this design is that it uses realism even in such small details.
Filtering is very useful when you deal with large amount of data. Use dropdowns, radio buttons or checkboxes to make filter selection. In the example below, builditwith.me uses dropdowns to filter the list of people by profession, interest and availability.
However, you can perform filtering only by predefined set of values. For instance, you can filter a list of jobs by it’s type: full-time/freelance or by type: design/development. This means you can’t filter by First/Last name because there is infinite number of variations. In this case you can use live filter which uses keywords to filter data. For live filter you use input field where users can type any keyword and list is filtered by keywords found in any column.
Builditwith.me has several filter options above the list and live filtering below it.
When dealing with large amount of data it is a good practice to split them in pages. Pagination is commonly used pattern but in many cases it is ineffective. This works for search engines but that doesn’t mean it will work in all cases.
Product Planner implements pagination in a common way – with page numbers and prev and next links. But can you tell what is on page 2? Page 3? Sure you can’t. But standard pagination can be improved. Take EveryBlock example shown below. Since it is a large addressbook, they used numbers and letters to define pages. Although in their case all pages are shown this would work well with hiding pages as well. You can use the similar approach for other criteria by which tables are sorted. If table is sorted by date, you can show date ranges instead of page numbers (Page 1 can be shown as Feb 10 – Feb 12, and so on).
If pagination links become too wide, you can use common page numbers (as seen in previous example) and show additional information while hovering over links.
As a contrast to pagination, continuous scrolling reveals new sets of data while you scroll down the list. There is no option to go to a specific set of data as it is the case with paging. Instead, new set of data is being added to a list. During the load time a progress indicator should be shown. In the example below, a progress indicator on dzone.com is showing how many items are loaded.
There are certain usability and accessibility issues with this pattern so you should test if this work with your users. You can read more about this pattern on UI Patterns.
There is a variation of this pattern (or actually another pattern) that doesn’t have such issues. Instead of revealing new set of data while scrolling, users can get the next set of data by clicking on more button, positioned at the end of the list. A good example of this can be seen on Twitter.
Fixed table header
This is a nice simple trick you can use to keep table header always visible. You can use it on fairly large and complex data sets to help users distinguish between many columns. I don’t have any live example so if you know one, please share! FixedHeaderTable plugin can be a good example.
If data in a table if self-explanatory there is no need for table header. A table that shows emails can be a good example – email subject, sender and date sent are self-explanatory and distinctive data which doesn’t require table header. However, there are cases when you won’t be able to remove table header. If there are ambiguous data, such as two dates, you would need a header description for these columns.
Rivalmap dashboard is a good example of headerless table. The information in the table is obvious and formatted in such way that no table header is needed.
I already wrote about this pattern and created a small jQuery plugin that you can easily implement. The key point of this pattern is to enable adding additional information or functionality to tables. BuySellAds, for example, uses this pattern to show advertising details about each publisher, while keeping the most important information always visible in master rows.
Tables are often much more than a plain placeholder for endless data. They also can be interactive elements that can perform specific actions. Actions are usually performed on a single row (they can be also performed on multiple rows, see next pattern). Actions can be shown inline, they can be revealed on hover or shown as a menu.
The simplest way to show actions is to place them in line with row data, at the beginning or the end of the row. In the example below, Mixx shows voting action at the end of each row which makes voting quite easy.
This is variation of the previous pattern that can be used in cases when you have multiple actions. By hiding them and revealing them on hover you declutter interface and make more space for data. Project Estimator by Astuteo shows edit and delete action on hovering each row.
If there are a lot of actions you can perform on each row, you can show them as a many that can be revealed on hover or click. DropBox utilizes this pattern very effectively. Since there are a lot of actions you can perform on each file, they show them as a context menu.
Actions on multiple rows
A good approach in many cases is to enable users to perform actions on multiple rows. Users can select rows by clicking on a checkbox, usually placed at the beginning of each row, and perform group action by pressing one of the available group action links or buttons. I will use DropBox in example also. Users can select multiple files and perform one of the group actions available from menu.
It is also a good practice to enable select all/deselect all functionality which instantly select or deselect all visible rows.
The article covered the basics of the most common table patterns and some live examples. If I missed something please let me know! I also recommend you reading two more articles about tables: Big Table issue that tries to find an solution for tables that are so big they no longer fit in the viewport, and 15 Tips for Designing Terrific Tables that shows many different contexts in which tables can be used.
Thanks to Theresa Neil, one of the authors of Designing Web Interfaces, you can read about three more patterns that she documented: Inline Editing, Super Wide Tables and In-column Filtering.