Drivn vs shadcn/ui — Separator Compared
Compare Drivn Separator vs shadcn/ui — an eight-line server-safe div versus a Radix-backed client component. Both copy-paste, one ships zero Radix deps.
Drivn's Separator and shadcn/ui's Separator both give you the one-pixel line that breaks a section into two — content above, content below — but they get there from opposite ends. shadcn/ui wraps @radix-ui/react-separator, a Radix primitive whose entire job is to render a div with the right ARIA role and a data-orientation attribute. The shadcn file imports SeparatorPrimitive.Root, marks itself 'use client', and forwards a decorative prop that flips the role between separator and none.
Drivn's Separator is eight lines of code with no Radix package, no client directive, and no decorative flag. The component file at @/components/ui/separator.tsx imports only React and the local cn() utility. A two-key styles object holds the horizontal and vertical rules — w-full h-px bg-border and h-full w-px bg-border — and the component renders a single <div role="separator"> with the matching class merged in. The orientation prop selects the rule; the className prop lets you add margin or colour.
The practical split is a tiny server-safe div versus a Radix-backed client component with an ARIA-toggle escape hatch. This page walks the runtime footprint, the two-prop API, the server-rendering story, and the className workflow so you can pick the flavour that fits.
Side-by-side comparison
| Feature | Drivn | shadcn/ui |
|---|---|---|
| Underlying primitive | Single div with role="separator" | @radix-ui/react-separator |
| Runtime UI dependencies | cn() utility only | @radix-ui/react-separator |
| Props | orientation, className | orientation, decorative, className |
| Client component | No — server-safe | Yes — 'use client' |
| ARIA role model | Always role="separator" | Toggles separator vs none via decorative |
| Orientation API | styles[orientation] lookup | data-[orientation] selectors |
| License | MIT | MIT |
| Copy-paste install |
The runtime footprint
shadcn/ui's Separator file is a thin re-export. It imports SeparatorPrimitive from @radix-ui/react-separator and renders SeparatorPrimitive.Root with a few default classes. The Radix package ships its own bundle — the primitive itself, the React adapter layer, and the shared helpers Radix uses across components — and that JavaScript lands in your bundle the moment you import the file.
Drivn's Separator imports React and the local cn() utility. That is the entire dependency list. Every class lives in the verbatim styles object below, copied from packages/drivn/src/registry/components/separator.ts. styles.horizontal is the full-width one-pixel-tall rule, styles.vertical is the full-height one-pixel-wide rule, and both use the bg-border token so the divider colour follows the theme along with every other border in the project. There is no Radix package, no decorative flag, and no Presence wrapper — just a div with the right class.
1 // Drivn — styles object, verbatim from the registry 2 const styles = { 3 horizontal: 'w-full h-px bg-border', 4 vertical: 'h-full w-px bg-border', 5 }
A two-prop API instead of three
Most Drivn components lean on a dot-notation compound API — Select.Trigger, Dialog.Content, Accordion.Item — but a divider has nothing to compound. The Separator is one element with two props: orientation ('horizontal' | 'vertical', default 'horizontal') and className. That is the entire public surface.
shadcn/ui adds a third prop, decorative (default true), which flips the rendered ARIA role between separator and none so screen readers can skip purely visual dividers. Drivn always renders role="separator" — the same role shadcn applies when decorative is false. The file lives in your codebase after install, so the one case where you want a non-semantic divider is a one-line edit: open the component and drop the role attribute. Treat the two-prop API as the floor, not the ceiling — anything you would have reached for decorative to fix is a className or a single edit away.
1 // Drivn — full component, verbatim from the registry 2 export function Separator({ 3 orientation = 'horizontal', 4 className, 5 }: SeparatorProps) { 6 return ( 7 <div 8 role="separator" 9 className={cn(styles[orientation], className)} 10 /> 11 ) 12 }
Server component by default
shadcn/ui's Separator is marked 'use client' because it forwards a ref through React.forwardRef into a Radix primitive, and Radix's primitives expect to run on the client. The moment you drop a Separator into a server component layout, you pull a client boundary into that slot.
Drivn's Separator has no client directive. It is a plain function that returns a div — no refs, no hooks, no event handlers, no Radix lifecycle. You can render it directly in a server component, inside a layout.tsx, in a marketing page that ships zero JavaScript. The bundle stays at zero bytes for this component. For a divider sitting between page sections in a server-rendered hub page (like /categories), that is the entire reason to reach for a primitive this small instead of pulling in a Radix package. The Card compound and most other Drivn primitives follow the same server-safe-when-possible rule.
1 // app/about/page.tsx — no 'use client' needed 2 import { Separator } from "@/components/ui/separator" 3 4 export default function AboutPage() { 5 return ( 6 <article> 7 <h1>About</h1> 8 <p>The first paragraph sets the scene.</p> 9 <Separator className="my-6" /> 10 <p>The next paragraph picks up after the break.</p> 11 </article> 12 ) 13 }
Styling and the className escape hatch
Both versions accept a className prop, and both merge it with a cn()-style utility so Tailwind's later-wins ordering still works. The differences are what each one starts with. shadcn/ui ships shrink-0 bg-border plus dimension classes split across the data-[orientation=horizontal] and data-[orientation=vertical] selectors, so styling has to follow the data-attribute API.
Drivn's styles.horizontal is w-full h-px bg-border and styles.vertical is h-full w-px bg-border — flat strings, no attribute selectors. To add margin, pass className="my-6"; to swap the colour, pass className="bg-primary"; to change thickness, pass className="h-0.5" on a horizontal one. Because the file is yours after install, anything that does not fit into a className is a one-line edit to the styles object. Pair the Separator with the Accordion to give grouped sections a visual break, or drop one between the body and footer of a panel layout.
1 <Separator className="my-6" /> 2 <Separator className="bg-primary h-0.5" /> 3 <Separator orientation="vertical" className="mx-4" />
Install Drivn in one command
Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.
npx drivn@latest createRequires Node 18+. Works with npm, pnpm, and yarn.
Frequently asked questions
No — Drivn's Separator does not have a decorative prop. It always renders role="separator" so assistive tech treats it as a thematic break. If you need a purely visual divider that screen readers should ignore, open the file at @/components/ui/separator.tsx and either drop the role attribute or change it to role="none". The component lives in your project after install, so the edit is a one-line change.
Yes. Drivn's Separator has no 'use client' directive, no refs, no hooks, and no event handlers — it is a plain function that returns a single div. You can render it inside layouts, server pages, and static marketing pages without pushing a client boundary, and the component contributes zero bytes to the client bundle for that route.
The vertical Separator uses h-full, so it stretches to the height of its parent. Render it inside a flex row or a sized container — a 24-pixel-tall toolbar, for example — and it fills that height as a one-pixel-wide rule. Outside a sized parent it collapses to zero height because there is no intrinsic content to measure.
Pass utility classes through className. The default uses bg-border and one pixel of thickness (h-px or w-px), but cn() merges with later-class precedence, so any className you pass wins. Try className="bg-primary" for a brand-coloured rule, className="bg-muted-foreground/20" for a softer divider, or className="h-0.5" to double the thickness on a horizontal one.

