Moving to TailwindCSS, Shadcn and Base UI in AdapTable
We rebuilt AdapTable's UI primitives on top of TailwindCSS + shadcn/ui and Base UI, giving our users a faster, more accessible and more easily themeable experience across AdapTable
AdapTable has always prided itself on shipping a rich, opinionated UI out of the box.
These include wizards, dashboard toolbars, tool panels, cell editors, pickers, dialogs, column & context menus, and a long tail of bespoke controls.
As our UI surface has grown, we decided it was time, with the release of AdapTable Version 23, to invest in the foundation that all of these components sit on.
Important
- AdapTable's component library has moved to TailwindCSS & shadcn/ui, layered on top of Base UI
- This gives AdapTable a modern, accessible, themeable, Tailwind-driven UI foundation
This post explains what has changed, and - more importantly - what this means for the developers and run-time users who rely on AdapTable every day to run business-critical applications.
What Changed Under the Hood
Previously, AdapTable shipped with a hand-rolled component set built up over many years.
It worked well, but maintaining dropdowns, popovers, comboboxes, tooltips, selects and menus from scratch - with full accessibility - is a significant undertaking.
More importantly, it was not core to what AdapTable does.
So we've adopted the combination that is fast becoming the default stack for serious React applications:
| Layer | Library | Role |
|---|---|---|
| Primitives | Base UI (@base-ui/react) | Unstyled, accessible, composable components |
| Patterns | shadcn/ui | Conventions for assembling and styling those primitives |
| Styling | Tailwind CSS + CSS variables | Utility-first styling and token-driven theming |
| Icons | Lucide | Consistent, tree-shakeable icon set |
Note
- Base UI is the headless component library from the team behind Radix UI and MUI - it provides the behaviour, accessibility and state management
- shadcn/ui is not a traditional npm package but a set of conventions and recipes for building your own component library on top of headless primitives
- This gives us the flexibility of owning our components, without the complexity of owning accessibility
This means every dropdown, popover, combobox, tooltip, menu and dialog in AdapTable is now built on the same small, well-tested set of primitives.
CSS Variable Renames
As part of this migration we have simplified some of our CSS custom property names to align with the shadcn/Tailwind conventions:
| Before | After |
|---|---|
--ab-color-defaultbackground | --ab-color-background |
--ab-color-text-on-defaultbackground | --ab-color-foreground |
--ab-color-inputcolor | --ab-color-input-foreground |
--ab-color-inputborder | --ab-color-input-border |
--ab__border-radius | --ab-border-radius |
If you were overriding the old variable name, you should transition to the new variable name.
For this release, the default values for the new variables still fallback to the old names if you have them, but they will be phased out in the next major release.
Better Accessibility (ARIA) Out of the Box
The biggest single win from this migration is accessibility.
Note
- Base UI implements the WAI-ARIA Authoring Practices for every primitive it ships
- Roles, states, relationships and focus management are all handled correctly by default
In practical terms, this means AdapTable UI now:
- announces menus, listboxes, comboboxes, dialogs and popovers correctly to screen readers
- exposes correct
aria-attributes:label,expanded,selected,controlsandactivedescendant - manages focus traps in modals and popovers, and restores focus when they close
- keeps
aria-labelledby/aria-describedbyrelationships consistent across our components
For users working in regulated environments - or simply users who rely on assistive technology - this is a material improvement on what we had before.
First-Class Keyboard Navigation
Hand-in-hand with ARIA comes first-class keyboard support.
Every interactive component in AdapTable - menus, comboboxes, selects, tabs, dialogs, tooltips - now follows the keyboard interaction patterns that advanced users expect:
Note
- Arrow keys navigate options in menus, selects and comboboxes
- Home / End jump to the first or last item
- Type-ahead jumps to matching items in menus and listboxes
- Escape closes popovers, dialogs and menus and returns focus to the trigger
- Tab / Shift+Tab follow a predictable focus order, including inside modal dialogs
- Enter / Space activate the currently focused item
This is particularly valuable for AdapTable's power users on trading floors and operations desks, who rely on keyboard-driven workflows and rarely reach for the mouse.
Cleaner, More Flexible Styling
Under the new system, every component is styled with Tailwind utility classes, driven by a small set of CSS variables (design tokens).
This provides mulitple benefits in a single step:
- Consistent theming - colours, spacing, radii and typography are derive from one set of tokens
- Built-in dark mode - light and dark themes are just two sets of CSS variable values
- Easier white-labelling - customers who need to match a corporate palette can do so by overriding a handful of CSS variables, rather than fighting with deeply nested selectors
- Smaller surface area for regressions - fewer bespoke stylesheets means fewer places for visual bugs to hide
No Clashes With Your Own Tailwind
A common (and entirely reasonable) concern when a library adopts Tailwind is: "what happens if my app is already using Tailwind, possibly at a different version, with my own utility classes?"
Important
AdapTable's Tailwind setup is fully scoped under a twa: prefix - so every utility class AdapTable emits looks like twa:bg-color-accent, twa:flex, twa:p-2, rather than the bare bg-color-accent, flex, p-2.
In practice, this means:
- No class-name collisions - AdapTable's
twa:flexand your app'sflexare two completely separate utilities, and can't overwrite each other - No version coupling - your app can stay on its current Tailwind version (v3, v4, or no Tailwind at all); AdapTable ships its own self-contained Tailwind build
- No configuration required - you don't need to extend your
tailwind.configor add AdapTable to yourcontent/@sourcepaths for anything to work - Safe to drop into any app - whether your host app uses Tailwind, styled-components, CSS modules, vanilla CSS, or a mix, AdapTable's styles stay inside their own namespace
Hint
- AdapTable fits right into applications already using Tailwind far more naturally than before
- Thanks to the
twa:prefix it does so without asking you to change your existing styling setup
Troubleshooting: cascade layer order
In rare cases - typically when your app uses Tailwind v4 with cascade layers and AdapTable's prefixed utilities appear to be overridden by your app's preflight reset (e.g. twa:px-1 losing to *, ::before, ::after { padding: 0 }) - declaring an explicit layer order in your global stylesheet resolves it:
@layer theme, base, components, adaptable, utilities;This places AdapTable's styles after your base (preflight) and components layers but before your own utilities, so AdapTable's prefixed classes win against the base reset while your own utility classes still win against AdapTable. The rightmost layer in the declaration has the highest priority.
Performance and Bundle Improvements
Rebuilding on top of Base UI and Tailwind also gave us an opportunity to clean up the bundle.
Note
- Headless primitives are lighter than their styled equivalents - there is no CSS-in-JS runtime involved
- Tailwind's utility classes compress extremely well, and produce a small, shared stylesheet rather than per-component style blocks
- Tree-shaking is more effective: we only ship the primitives we actually use
For end users this manifests itself in 2 noticeable ways:
- a much faster intitial render
- smoother subsequent UI interactions
This is particularly noticeable on large, data-dense screens (where AdapTable is often used).
What Stays the Same
Important
This is an internal UI refresh - not a breaking change for consumers of AdapTable
- All existing AdapTable modules, APIs and config options continue to work exactly as before
- Existing styling and theming APIs are preserved
- Your existing custom toolbars, custom cell renderers, custom context menus and Adaptable Buttons all continue to work unchanged
If you upgrade and do nothing else, the main thing you will notice is that the UI feels a little snappier, a little cleaner, and a lot more consistent.
le for yourself.