Drivn vs shadcn/ui — Alert Component Compared
Side-by-side comparison of Drivn and shadcn/ui React Alert components — variants, icon prop, cva dependency, and role=alert accessibility defaults.
Every app eventually needs a way to tell the user something changed — a payment failed, a file uploaded, a trial is about to lapse. Both Drivn and shadcn/ui answer that need with an Alert you copy into your own codebase and own outright, yet the two components make different bets about API surface, variant coverage, and accessibility. This page puts them next to each other with code from both sources so the choice rests on behavior, not branding.
shadcn/ui models its Alert as three composable exports — Alert, AlertTitle, and AlertDescription — that you nest by hand. Variant logic runs through class-variance-authority layered on clsx, and the library ships two states out of the box: default and destructive. The outer container also sets role="alert", so a screen reader announces the content the moment it enters the DOM.
Drivn takes the opposite tack. Its Alert is one component that reads variant, title, icon, and children as props, ships four variants (default, info, success, destructive), and resolves classes through a plain const styles object typed by keyof typeof. There is no cva, no clsx, and — at install time — no ARIA role on the wrapper.
Fewer wrappers or a built-in announcement, four variants or two, prop ergonomics or structural composition: the sections below weigh each trade with side-by-side code so you decide on how the component actually behaves rather than on a tagline.
Side-by-side comparison
| Feature | Drivn | shadcn/ui |
|---|---|---|
| Runtime UI dependencies | None (React + Tailwind) | cva + clsx |
| Variant count | 4 (default, info, success, destructive) | 2 (default, destructive) |
| API shape | Single component + props | 3 named exports (Alert, AlertTitle, AlertDescription) |
| Icon prop | icon={Info} (component ref) | children (JSX element) |
| Title slot | title="..." prop | <AlertTitle>...</AlertTitle> |
| role="alert" by default | ||
| Variant API | const styles + keyof typeof | class-variance-authority (cva) |
| License | MIT | MIT |
| Copy-paste install |
API side-by-side
shadcn/ui's Alert is three components that you nest together — Alert, AlertTitle, and AlertDescription — plus any icons passed as direct children. Drivn's Alert is a single component that takes variant, icon, title, and children as props, so a typical usage is one line of JSX rather than four or five. The render output is almost identical; what differs is how you author it and how many imports the file needs at the top.
For developers who prefer structural composition, shadcn's named-export pattern is familiar — it matches how the broader Radix ecosystem expresses component parts. For developers who prefer prop-driven ergonomics, Drivn's single-component shape eliminates wrapper JSX and keeps the whole alert on one visual line. Neither is objectively better; choose on how your codebase prefers to read. You can install either via the CLI in under a minute.
1 // shadcn/ui — three named imports 2 import { 3 Alert, 4 AlertTitle, 5 AlertDescription, 6 } from '@/components/ui/alert' 7 import { Info } from 'lucide-react' 8 9 <Alert> 10 <Info className="h-4 w-4" /> 11 <AlertTitle>Heads up</AlertTitle> 12 <AlertDescription> 13 Your trial expires in 3 days. 14 </AlertDescription> 15 </Alert> 16 17 // Drivn — one import, prop API 18 import { Alert } from '@/components/ui/alert' 19 import { Info } from 'lucide-react' 20 21 <Alert variant="info" icon={Info} title="Heads up"> 22 Your trial expires in 3 days. 23 </Alert>
Variant set
Out of the box shadcn/ui gives you two Alert variants — default and destructive — and leaves anything else to a cva edit. Drivn ships four: default, info, success, and destructive. Each one arrives pre-tuned with a border color, a background tint, and a text token that already tracks the Drivn palette, so an informational banner or a green success confirmation renders correctly the instant you drop it in, with no variant configuration step.
That gap matters most for products that surface several feedback states at once — a status bar on a dashboard, a post-submit success note, a quota warning near a limit. There the extra info and success presets remove a repetitive round of cva wiring on every project. If your UI only ever shows errors, the count is a wash. See how Alert sits alongside Toast, Progress, and Tooltip in the feedback category, and how the same token approach powers theming across the whole set.
Icon prop vs children
shadcn/ui's Alert accepts icons as direct children: you render an icon element (usually a Lucide icon) before the AlertTitle and AlertDescription inside Alert. Drivn inverts this: the icon is a prop, and you pass the icon component by reference — icon={Info} — or as a pre-rendered element — icon={<Info className="size-5" />}. The component then decides where the icon sits, how it aligns with the title, and what size it renders.
In practice the prop API means fewer wrapper elements and less class-name plumbing per alert. You do not need to know the icon's size class or flexbox rules; Drivn's internal flex layout handles spacing. For teams that want per-alert icon styling, passing a pre-rendered element gives full control. The pattern matches Drivn's Button with its leftIcon prop, so once you learn it, it stays consistent across the library.
Accessibility and role="alert"
shadcn/ui's Alert applies role="alert" to the container by default, which signals to assistive technology that the content is time-sensitive and should be announced immediately when it appears. Drivn's current Alert does not set this role — it renders a plain div with Tailwind classes. For a persistent banner that sits on the page from render onward, this is often fine because the user reads it in normal document order. For an alert that appears dynamically in response to an event — a failed save, a successful upload — the missing role means a screen reader may skip the announcement entirely.
If accessibility announcements matter for your use case, the fix is a one-line edit in the component file after install: add role="alert" to the outer div in src/components/ui/alert.tsx. Because the source lives in your repo, you own this change permanently. For transient confirmations that need to announce themselves regardless of role, the Toast component is the stronger choice — toasts are built with a live-region announcement from the start.
Customization
shadcn/ui's Alert variants live inside a cva configuration. To add a success variant you extend the variant record, add Tailwind classes for the color scheme, and update the type. Drivn's variants live inside a plain const styles object: each key maps to a Tailwind class string, and the keyof typeof styles.variants type gives you autocomplete at the call site. Adding a new variant is literally adding a key.
Color tuning lives in the Drivn theming system — --color-success, --color-primary, and --color-destructive are all HSL tokens, so switching from one brand palette to another is a variable change, not a class-by-class find and replace. If you want a new variant that is not on the default list — warning, promo, muted — the pattern is: add the key, pick the HSL token, the type narrows automatically. Neither library hides complexity; both let you reach the underlying styles without fighting the API.
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
Not by default. The current Drivn Alert renders a plain div without an ARIA role. For static banners rendered on page load this is usually fine — the user reads the alert in document order. For dynamically inserted alerts, a screen reader may skip the announcement. The fix is a one-line edit to the component file: add role="alert" to the outer div in src/components/ui/alert.tsx after install. Because Drivn components live in your repo, this customization is permanent.
Open src/components/ui/alert.tsx after install and add a new key to the styles.variants object — for example warning: 'bg-yellow-500/10 border-yellow-500/20 text-yellow-600'. The keyof typeof styles.variants type that powers the variant prop picks up the new key automatically, so TypeScript autocompletes warning at every call site with no other changes. If you want the new variant to use a design token rather than a hardcoded color, add a CSS variable in globals.css and reference it from the class list.
Yes. The icon prop accepts either a component reference (icon={Info}) or a pre-rendered React element (icon={<Info className="size-5" />}). Pass any Lucide icon, any custom SVG component, or any component that matches the ComponentType<{ className?: string }> signature. The pre-rendered element form is useful when you need per-alert icon styling that overrides the default — a larger icon in a hero banner, or a different color for a specific callout.
Three things at the time of writing: the default role="alert" ARIA role, the named-export composition style (AlertTitle, AlertDescription), and the cva-based variant configuration pattern. None of these are blockers — the ARIA role is a one-line addition, the named exports are an authoring preference rather than a behavioral difference, and cva is an alternative variant API rather than a requirement. For most teams the missing pieces are rounding errors; for teams heavily invested in Radix conventions, they can still matter.

