Name | Email | Skills | Bonus | Last Login | Birthday |
|---|
As a forecasting, analytics, and scheduling tool, Assembled relies on tables in nearly every core workflow. The team was reimplementing common patterns (e.g., pagination, sorting, and filtering) from scratch on each page, leading to redundant code and slower build times. With a growing number of enterprise customers like Stripe, Salesforce, and DoorDash, we needed a robust, reusable table component to help us build features faster while guaranteeing high-quality user experiences.
I began by auditing existing tables throughout the product to identify the features we needed to support out of the box. I collaborated with the Design Team to understand what table-related features we needed to support within the next quarter to meet customer commitments, which helped prioritize essential (e.g., nested rows, column pinning, etc.) versus nice-to-have (e.g., resizable columns, etc.).
I researched multiple library options TanStack Table, AG Grid, Material UI, etc. and built prototypes to evaluate their performance and flexibility against our requirements. I also researched accessibility best practices for tables to ensure our component would be accessible to users who rely on assistive technologies.
Every table I've created has been unique. They all behave differently, have specific sorting and grouping requirements, and work with different data shapes. It doesn't make sense to stuff all of these variations into a single component (i.e., a monolith with dozens of props).


I built a set of components and utilities on top of TanStack Table primitives, the system is a set of composable pieces—each bakes decisions around look, feel, and behavior, but has no opinions about what sits next to it. A column header knows how to render a sort indicator, a resize handle, and proper accessibility labels. It doesn't know or care whether the table has pagination. A pin toggle cycles through pin states and swaps its icon. It doesn't know whether sorting exists.
Authors could compose only the pieces a page actually needed. For example, for a basic, no-frills set up:
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });
return (
<DataTable>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<TableColumnHeader key={header.id} {...header}>
{flexRender(header.column.columnDef.header, header.getContext())}
</TableColumnHeader>
))}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows.map((row) => (
<TableRow key={row.id}>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</DataTable>
);The architecture stacks in layers. At the bottom: thin wrappers over native HTML table elements that lock in consistent styling—borders, spacing, overflow—with zero props. One level up: a data table shell that adds structural behavior like sticky headers. Then individual feature components—sort toggles, pin toggles, resize handles, a drag-to-reorder column menu—each owning exactly one concern.
Teams didn't need to learn TanStack to start using it effectively. Our table leveraged the TanStack's meta api for localization and native sorting functions out of the box. Need a basic sortable table? Import the base, add column headers with sort toggles. Need pinning? Drop in the pin toggle. Need column reordering? Add the menu. Each piece works independently, so you adopt incrementally—no all-or-nothing migration. I worked with the Design team to make sure every component carried our design system's opinions, and documented the full system in Storybook with composition examples for the most common patterns.
Within a year of its initial rollout, the table component was adopted on over 90% of report pages (36 in total) by every team across the organization (40 engineers). The component's built-in features—including expandable parent-child rows, row virtualization for large datasets, and advanced data display capabilities—enabled teams to unblock feature work for strategic customers. This increased productivity for both developers and designers while delivering improved performance and more efficient data visualization across the product.