chore(docs): Add example of a full-page sortable table - #2516
Conversation
Use 300 real Amsterdam BAG address records as mock data for Data Table examples instead of the Eredivisie football ranking.
There was a problem hiding this comment.
Pull request overview
This PR adds a new internal Storybook page (“Table Page”) that demonstrates rendering a realistic, sortable data table using the design system’s Table component and mock BAG address data.
Changes:
- Add a new Storybook internal page with a sortable address table controlled via a
Select. - Introduce a typed mock dataset (
BagAddress) and asortAddressesutility plus sort options. - Add page-specific documentation and styling for the internal page layout.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| storybook/src/pages/internal/TablePage/TablePage.stories.tsx | New internal page story rendering the sortable table UI. |
| storybook/src/pages/internal/TablePage/TablePage.docs.mdx | Documentation for the Table Page patterns and state-sharing guidance. |
| storybook/src/pages/internal/TablePage/table-page.css | Styling intended to support the “full-page” layout presentation. |
| storybook/src/pages/internal/TablePage/common/sortAddresses.ts | Sorting helper for ordering the address dataset by selected field/direction. |
| storybook/src/pages/internal/TablePage/common/options.ts | Sort option definitions and derived SortOrder type. |
| storybook/src/pages/internal/TablePage/common/index.ts | Barrel exports for the Table Page common utilities/components. |
| storybook/src/pages/internal/TablePage/common/bagAddresses.ts | Typed BAG address mock dataset. |
| storybook/src/pages/internal/TablePage/common/AddressTableHeaderRow.tsx | Table header row component for the address table. |
| storybook/src/pages/internal/TablePage/common/AddressTableBody.tsx | Table body renderer for the address rows and empty state. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dlnr
left a comment
There was a problem hiding this comment.
Good start! I would also love to see search and pagination at some point.
There was a problem hiding this comment.
I agree that it is a good start, but a few remarks.
Multi-column sorting
With complex data tables you often want to have multi-column sorting. Where data is in one column is closely related to data in another column, and it doesn't make sense to sort it independently.
With the current dataset and sorting options users can sort on huisnummer. But does that make sense? Why would someone want to sort on huisnummer if there is no connection with the straat column?
I do see that columns that are not sorted upon via the select are always sorted A-Z if there are multiple rows for a value in the currently sorted-on column, i.e. "Korte 's-Gravesandestraat 4" comes before "Nieuwe Achtergracht 4" when sorting on huisnummer.
Common pattern to have carets or arrows in the table's header
Often complex data tables have arrows in the table's header row to allow direct sorting of that column. I think this may have a few advantages:
- It might be more intuitive for users; they can directly click on something to affect it, and they are probably used to the pattern.
- It's immediately visible what column is (not) sorted upon.
- It does allow for multi-column or connected sorting.
I briefly looked for accessibility concern. I found that w3 and thewcag have examples with said arrows.
Note that even if the arrows are not interactive, they can still exist to give visual feedback.
Does the decision to expand the existing Table for more complex data usage prevent this pattern? Or are there other reasons not to use this pattern?
Reactive components
Our tables are components are currently stateless and not reactive. Remember the criticism from some about Pagination where a new request to the server had to be done to refresh the view.
I suspect that as we provide more documentation on how to turn the basic Table into more complex data tables we'll get more feedback that developers want to have the option to fetch data and update the view dynamically. Or they will create their own workarounds to get what they want. This is already happening I can tell you. Can we work with those developers somehow and allow for more ways to use our components?
Thanks for this thoughtful feedback.
Sorting through a Select is just one pattern that we intend to offer as an example. Some others can be found in Amsterdam/design-system-prototypes#652. Multi-column sorting could surely follow.
Yes, this column might be not the best example.
Do we agree that this is expected?
This is also a pattern we intend to offer. It’s partially implemented in the prototypes poc.
No, it’s just that this branch introduces only one pattern. This makes the PR easier to review. And it allows feedback on this table example to be applied to the next ones from the start.
This is also reactive, no? <Table>
{data.map(row) => (
<Table.Row>
<Table.Cell>{row.value1}</Table.Cell>
<Table.Cell>{row.value2}</Table.Cell>
<Table.Cell>{row.value3}</Table.Cell>
</Table.Row>
)}
</Table>If
We’ve discussed this earlier in the front-end guild. Let’s do that once more if we have a couple of patterns up and running. State management can be added later if necessary, it would probably not break the API. |
I guess it's okay, but currently, it when a user first sorts Straat from Z-A and then Huisnummer from Z-A, Straat (and all other columns) reset to A-Z sorting. It would be nice if that reset didn't happen, but it remembered the last sorting. I think this is possible in JavaScript, by just not touching any other columns than the one the user is now actively sorting on. This way you already get the multi-column sorting functionality to some extent.
You're right that the data in the table view will re-render if the provided data changes, but typically the data will come paginated from some API (very sensible when you're dealing with large datasets). Our Pagination currently works with links and not buttons which means that client-side sorting (or filtering for that matter) on the current view does not make much sense because the entire page has to be refreshed. I know that multiple teams do not respect this approach and have their own implementations to allow for data tables that fetch data programmatically with buttons while still using the design system's CSS styling. This is indeed a discussion that we need to have again. |
|
We agreed to pick up multi-column sorting with a later example, and to address the ‘links in single page applications’ approach in an upcoming meeting of our front-end guild. |
|
/chromatic test |
Add example of a full-page sortable table
Thank you for contributing to the project!
Please use this template to help us handle your PR smoothly.
What
A new “Table Page” in Storybook’s internal pages section with a realistic data table example.
It demonstrates sorting via a Select control, using 300 Amsterdam BAG address records as mock data.
Why
Teams using the design system have been asking for realistic examples of tables with features like sorting, filtering and pagination.
This page is the first of a few that will show how to build these patterns with our components.
How
Table.Captionfor its accessible label.sortAddressesutility handles sorting on any field, including optional values.SortOrdertype is derived fromsortOptionsviaas const, so the type narrows to only the offered sort values.Checklist
/chromatic testand verify visual regression tests passAdditional notes