[Bug Fix] DataTable: match dashboard-01 look (Columns trigger, badges, toolbar spacing)

Merged
CI
5h ago
+73-8

Follow-up to #579 (stacked on it). It fixes the visual differences the shadcn audit still reported on DataTable against the dashboard-01 block (Base UI + vega + neutral). #579's per-page Select and CSP change is left alone.

What changed

Columns toggle (display: inline-flex vs flex).

Both buttons have the same inline-flex class. shadcn's trigger computes flex because it is a direct child of the toolbar's div.flex, and a flex item's inline-flex becomes flex. In RubyUI, DataTableColumnToggle's div.relative and the DropdownMenu root sat between the toolbar and the button, so the button stayed in block flow. Both wrappers are now display: contents. The menu is a top-layer popover anchored to the button, so it doesn't rely on either wrapper's box. Button and DropdownMenu are unchanged.

Row checkbox (block; text-align: start vs flex; text-align: left).

RubyUI's checkbox is a native <input type=checkbox> with no children; its check mark is an absolutely positioned ::before. shadcn's is a <span class="flex"> that centers its Indicator child. flex only affects children, so on the input it renders the same box as block. The text-align line comes from the select-all checkbox in the header: the browser's form-control defaults reset the input to start, while the span inherits left from TableHead. In LTR the two are the same. Both are registered in audit/divergences/data_table.yml, and Checkbox is unchanged.

"In Process" / "Done" badges look darker.

This came from the audit fixture, not Badge. RubyUI used Badge(variant: :outline, size: :sm) (h-4, text-foreground). The block uses the default size with px-1.5 text-muted-foreground, puts the type badge in a div.w-32, and shows a status icon: CircleCheckIcon with fill-green-500 dark:fill-green-400 for Done, LoaderIcon otherwise. The shadcn fixture was missing those icons too. Both fixtures now follow the block, and computed color, size, padding, border and icon fill/stroke match in light and dark.

Toolbar to table spacing.

The re-run showed one more difference: RubyUI's table sat 8px higher. DataTable uses space-y-4 (16px), while the block's Tabs root has gap-6 (24px) between the toolbar and the table (and gap-4 between the table and the pagination). DataTableToolbar now has mb-6, which overrides space-y-4's zero-specificity margin below the toolbar only.

After these changes the per-state pixel diff dropped from about 26k px (light) and 44k px (dark) to 33 px in every state (closed, open, focus, after-esc). The 33 px are the font fallback on "row(s)", the environment difference the audit already reports.

Screenshots

Each image is RubyUI on main + #579, RubyUI with this PR, and shadcn (Base UI + vega).

closed (light)

closed (dark)

open (light)

open (dark)

Audit checklists

Before (main + #579)
shadcn audit  ruby-ui/ruby_ui
  base 1fd93db0  head 78c4c242  shadcn 42f3bb63
⚠️ Environment  font: "Inter Variable", "system-ui", -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, "sans-serif" vs "Inter Variable", sans-serif (light)
⚠️ Environment  font: "Inter Variable", "system-ui", -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, "sans-serif" vs "Inter Variable", sans-serif (dark)
✅ Theme  neutral tokens match shadcn
DataTable  (ref: bases/base/blocks/dashboard-01/components/data-table.tsx + style-vega.css @ 42f3bb63)
  ❌ Look       display: inline-flex
               vega: display: flex
               DataTableColumnToggle — closed/light, open/light, focus/light, after-esc/light, closed/dark, open/dark, focus/dark, after-esc/dark
               ↳ computed styles (shadcn-audit collect)
  ❌ Look       display: block; text-align: start
               vega: display: flex; text-align: left
               DataTableRowCheckbox — closed/light, open/light, focus/light, after-esc/light, closed/dark, open/dark, focus/dark, after-esc/dark
               ↳ computed styles (shadcn-audit collect)
  ⏸ Look       properties: font-family
               DataTableColumnToggle, DropdownMenuContent, DataTablePerPageSelect, DataTableRowCheckbox — explained by environment diff: font
  ✅ ARIA       DataTableColumnToggle, DropdownMenuContent, DataTablePerPageSelect, DataTableRowCheckbox: accessibility tree matches
               ↳ accessibility tree (shadcn-audit collect)
  ❌ Look       status/type badges: Badge(variant: :outline, size: :sm) → h-4 text-foreground, no status icon
               vega: Badge variant=outline className="px-1.5 text-muted-foreground" → h-5 text-muted-foreground; Done: CircleCheckIcon fill-green-500 dark:fill-green-400, otherwise LoaderIcon; type badge inside div.w-32
               Fixture composition (and the shadcn fixture lacked the block's status icons): the badges read darker and shorter on RubyUI.
               ↳ bases/base/blocks/dashboard-01/components/data-table.tsx:194
  ❌ Look       DataTable space-y-4: 16px between toolbar and table
               vega: Tabs root gap-6: 24px between toolbar and table (16px table → pagination, gap-4)
               The table sits 8px higher on RubyUI.
               ↳ bases/base/blocks/dashboard-01/components/data-table.tsx:434
After (this PR)
shadcn audit  ruby-ui/ruby_ui
  base 1fd93db0  head 6e0a3ea9  shadcn 42f3bb63
⚠️ Environment  font: "Inter Variable", "system-ui", -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, "sans-serif" vs "Inter Variable", sans-serif (light)
⚠️ Environment  font: "Inter Variable", "system-ui", -apple-system, "system-ui", "Segoe UI", Roboto, "Helvetica Neue", Arial, "sans-serif" vs "Inter Variable", sans-serif (dark)
✅ Theme  neutral tokens match shadcn
DataTable  (ref: bases/base/blocks/dashboard-01/components/data-table.tsx + style-vega.css @ 42f3bb63)
  ✅ Look       text-align: start — intentional
               DataTableRowCheckbox — In a left-to-right document start resolves to left, and the input has no text to align either way.
               ↳ audit/divergences/data_table.yml
  ✅ Look       display: block — intentional
               DataTableRowCheckbox — flex only lays out children, and the native input has none (its check mark is an absolutely positioned ::before), so block and flex render the same box. Adding flex to the input would change nothing on screen.
               ↳ audit/divergences/data_table.yml
  ⏸ Look       properties: font-family
               DataTableColumnToggle, DropdownMenuContent, DataTablePerPageSelect, DataTableRowCheckbox — explained by environment diff: font
  ✅ ARIA       DataTableColumnToggle, DropdownMenuContent, DataTablePerPageSelect, DataTableRowCheckbox: accessibility tree matches
               ↳ accessibility tree (shadcn-audit collect)
  ✅ Look       DataTableColumnToggle: wrapper and DropdownMenu root display: contents → button is a toolbar flex item, computes display: flex
               inline-flex blockifies to flex in a flex container; the RubyUI wrappers had kept the button in block flow.
               ↳ bases/base/blocks/dashboard-01/components/data-table.tsx:475
  ✅ Look       Badge(variant: :outline, class: "px-1.5 text-muted-foreground") + lucide circle-check (fill-green-500 dark:fill-green-400) / loader; type badge in div.w-32
               Fixture only, Badge unchanged. Computed color, size, padding, border and icon fill/stroke match, light and dark.
               ↳ bases/base/blocks/dashboard-01/components/data-table.tsx:194
  ✅ Look       DataTableToolbar mb-6: 24px before the table, 16px table → pagination
               Pixel diff per state down from ~26k (light) / ~44k (dark) px to 33 px (font fallback on "row(s)").
               ↳ bases/base/blocks/dashboard-01/components/data-table.tsx:434

Test steps

  1. cd gem && bundle exec rake (782 runs + new toolbar and toggle tests, standardrb clean).
  2. cd audit && bundle exec rake test and cd mcp && bundle exec rake test.
  3. /shadcn-audit data_table: the Look lines for DataTableColumnToggle and DataTableRowCheckbox no longer fail, and the per-state pixel diff is about 33 px.
  4. On /docs/data_table_demo, the Columns menu still opens, toggles columns and returns focus on Esc.

The base branch pierry01/data-table-per-page-select is an unchanged copy of #579's head (78c4c242), because GitHub stacks don't take fork PRs. Merge #579 first, then retarget this PR to main.

🤖 Generated with Claude Code