[Feature] Separator: match shadcn (Base UI + vega)

Merged
CI
2d ago
+381-41

Brings Separator in line with shadcn (Base UI + vega), following the shadcn audit of the component.

Changes

  • A vertical separator used h-full, which resolves to 0px in a flex row with no fixed height, so it disappeared (Base UI's "Vertical Menu" example). It now uses self-stretch like shadcn and fills the row. Horizontal is h-px w-full, vertical w-px self-stretch.
  • Separator now renders data-slot="separator" and data-orientation, like Base UI. shadcn picks its classes through the data-horizontal:/data-vertical: custom variants from shadcn/tailwind.css. RubyUI's Tailwind setup doesn't define them, so the classes are still chosen in Ruby; the pixels match.
  • The default role is now role="separator" with aria-orientation, as in shadcn. decorative: true still renders role="none", but it is now opt-in (default false). This changes the default: separators that relied on being hidden from screen readers now need decorative: true.
  • With as: :hr there is no explicit role, since <hr> already has the separator role (ARIA in HTML). aria-orientation is only added when vertical. Tailwind's preflight sets hr { height: 0; border-top-width: 1px }, so border-0 keeps an <hr> at 1px instead of 2px, and a vertical <hr> also gets h-auto (without it, self-stretch leaves it at 0px).
  • Docs view rewritten with shadcn's examples (Horizontal, Vertical, Vertical Menu, In List) plus Decorative and <hr>.
  • Separator joins the audit: audit/component_map/separator.yml (baseline 8a35366) and audit/fixtures/separator/.
  • MCP registry rebuilt.

SidebarSeparator and FormFieldSeparator render through Separator. The sidebar's w-auto still overrides w-full through tailwind_merge.

Before / after

Left to right: RubyUI on main, RubyUI on this PR, shadcn (Base UI + vega). On main the separator between Settings and Account is missing.

closed (light)
closed (dark)

Audit on main
shadcn audit  ruby-ui/ruby_ui
  base 25ccda6b  head 25ccda6b  shadcn 8a353667
⚠️ 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
Separator  (ref: bases/base/ui/separator.tsx + style-vega.css @ 8a353667)
  ✅ Look       horizontal: shrink-0 bg-border h-[1px] w-full; vertical in h-5 row: 1px × 20px
               h-[1px]/h-px and w-[1px]/w-px compute the same; colors match light and dark. Requested: commit audit/component_map/separator.yml + audit/fixtures/separator/ (created during this audit) and run `baseline separator 8a3536678a528cc012b9e62484290e79d0be410f` in the fix PR.
               ↳ bases/base/ui/separator.tsx:16
  ❌ Look       vertical: h-full w-[1px] → 0px tall in the auto-height row (Vertical Menu)
               vega: vertical: data-vertical:w-px data-vertical:self-stretch → 40px (stretches to the row)
               Override of collect's ⏸: font-family is the environment diff, but height is not: h-full resolves to auto in a flex row with no definite height, self-stretch fills the row. Fixed-height row (h-5) renders the same (20px both). Requested: vertical uses self-stretch instead of h-full (and h-px/w-px), via shadcn's data-horizontal:/data-vertical: classes.
               ↳ bases/base/ui/separator.tsx:16
  ❌ HTML       <div role="none" class="…"> (no data-slot, no data-orientation)
               shadcn: <div data-slot="separator" data-orientation="horizontal|vertical" role="separator" aria-orientation="…">
               data-orientation is what shadcn's data-horizontal:/data-vertical: classes key on; RubyUI picks classes in Ruby instead. Requested: emit data-slot="separator" and data-orientation, and switch to shadcn's data-horizontal:/data-vertical: class string.
               ↳ bases/base/ui/separator.tsx:13
  ✅ Props      orientation:, as:
               rubyui_only: decorative (Radix-era prop; Base UI dropped it).
               ↳ bases/base/ui/separator.tsx:8
  ⚠️ ARIA       role="none" (decorative: true by default) → no separator in the a11y tree; decorative: false gives role="separator" but no aria-orientation on vertical
               shadcn: role="separator" aria-orientation="horizontal|vertical", always (Base UI has no decorative prop)
               Separator — closed/light, closed/dark. A vertical role=separator without aria-orientation is announced as horizontal (implicit value). Requested: default role="separator" + aria-orientation like shadcn; keep decorative: as opt-in (default false) rendering role="none". Default changes: note it in the changelog.
               ↳ @base-ui/react/separator/Separator.js (sandbox, 1.9.0)
  ✅ Behavior   none (no controller)
               Non-focusable static separator on both sides.
               ↳ bases/base/ui/separator.tsx:5
  ✅ Animation  none
               ↳ bases/base/ui/separator.tsx:16
  ⚠️ Native     as: :hr renders <hr role="none"> by default (decorative: true strips the hr's implicit separator role); default element is <div>
               shadcn: <div role="separator">
               <hr> is the native separator; RubyUI offers it but removes its semantics unless decorative: false. The docs example uses as: :hr. Requested: with as: :hr, omit the explicit role (implicit separator; redundant role per https://www.w3.org/TR/html-aria/#docconformance), emit aria-orientation only when vertical, role="none" only with decorative: true.
               ↳ https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element/hr
  ✅ Spec       — follows spec
               shadcn's observed markup conforms (static separator, no value attributes needed).
               ↳ https://www.w3.org/TR/wai-aria-1.2/#separator

Audit on this PR
shadcn audit  ruby-ui/ruby_ui
  base 25ccda6b  head 3147f0a8  shadcn 8a353667
⚠️ 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
Separator  (ref: bases/base/ui/separator.tsx + style-vega.css @ 8a353667)
  ✅ Look       horizontal: shrink-0 bg-border h-px w-full; vertical: w-px self-stretch (1px × 20px in h-5 row, 1px × 40px in auto-height row)
               All 4 separators measure the same on both sides; pixel diff 0 in light and dark. Classes picked in Ruby: RubyUI's Tailwind setup has no data-horizontal/data-vertical custom variants (they come from shadcn/tailwind.css).
               ↳ bases/base/ui/separator.tsx:16
  ⏸ Look       properties: font-family
               Separator — explained by environment diff: font (font fallback list only; sizes match per element).
  ✅ HTML       <div role="separator" aria-orientation="…" data-slot="separator" data-orientation="…">
               ↳ bases/base/ui/separator.tsx:13
  ✅ Props      orientation:, as:
               rubyui_only: decorative (Radix-era prop; Base UI dropped it).
               ↳ bases/base/ui/separator.tsx:8
  ✅ ARIA       role="separator" aria-orientation="horizontal|vertical" by default; decorative: true → role="none"
               Accessibility tree matches (closed/light, closed/dark). decorative: is now opt-in (default false).
               ↳ @base-ui/react/separator/Separator.js (sandbox, 1.9.0)
  ✅ Behavior   none (no controller)
               Non-focusable static separator on both sides.
               ↳ bases/base/ui/separator.tsx:5
  ✅ Animation  none
               ↳ bases/base/ui/separator.tsx:16
  ✅ Native     as: :hr renders <hr> with its implicit separator role (no role attribute), aria-orientation only when vertical, border-0 to drop the preflight top border — native
               Redundant role avoided per https://www.w3.org/TR/html-aria/#docconformance.
               ↳ https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element/hr
  ✅ Spec       — follows spec
               shadcn's observed markup conforms (static separator, no value attributes needed).
               ↳ https://www.w3.org/TR/wai-aria-1.2/#separator

Test steps

  1. cd gem && bundle exec rake
  2. cd audit && bundle exec rake
  3. cd docs && bin/dev, open /docs/separator: the Vertical Menu separators span the row height, and the <hr> example is 1px.
  4. In the inspector: a default separator has role="separator" aria-orientation="horizontal" data-slot="separator" data-orientation="horizontal"; decorative: true gives role="none" with no aria-orientation.

🤖 Generated with Claude Code


Summary by cubic

Brings Separator in line with shadcn (Base UI + vega). Breaking change: decorative: now defaults to false — separators render role="separator" with aria-orientation by default; use decorative: true (role="none") for purely visual lines.

  • Vertical separators use w-px self-stretch instead of h-full, fixing the 0px-tall rendering in flex rows without a fixed height.
  • The component emits data-slot="separator" and data-orientation; class strings match shadcn's (h-px w-full, w-px self-stretch).
  • as: :hr omits the redundant role, adds aria-orientation only when vertical, and drops preflight's border.
  • Docs view rewritten with shadcn's examples; adds the separator to the audit with fixtures and rebuilds the MCP registry.