Skip to content
Drivn logoDrivn
6 min read

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.

React alerts tell users something has changed — a subscription expires, a form fails, a file saved successfully. Drivn and shadcn/ui both ship this component as editable source code rather than an npm wrapper, but the implementations diverge in variant count, API shape, and accessibility defaults. This comparison walks through each difference with real code from both libraries.

shadcn/ui exposes three named exports (Alert, AlertTitle, AlertDescription), uses class-variance-authority with clsx for variant plumbing, and ships two variants: default and destructive. The container carries role="alert" so assistive technology announces the content when it appears mid-page.

Drivn's Alert is a single component. It accepts variant, title, icon, and children as props, ships four variants (default, info, success, destructive), and drives styling through a plain const styles object indexed by a keyof typeof type. There is no cva or clsx wrapper and no built-in ARIA role at install time.

Which library fits better depends on what you value — fewer wrappers or default accessibility announcement, four variants out of the box or two, prop-driven ergonomics or structural composition. The sections below compare both on each dimension, with side-by-side code, so you choose on behavior rather than homepage copy.

Side-by-side comparison

FeatureDrivnshadcn/ui
Runtime UI dependenciesNone (React + Tailwind)cva + clsx
Variant count4 (default, info, success, destructive)2 (default, destructive)
API shapeSingle component + props3 named exports (Alert, AlertTitle, AlertDescription)
Icon propicon={Info} (component ref)children (JSX element)
Title slottitle="..." prop<AlertTitle>...</AlertTitle>
role="alert" by default
Variant APIconst styles + keyof typeofclass-variance-authority (cva)
LicenseMITMIT
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
2import {
3 Alert,
4 AlertTitle,
5 AlertDescription,
6} from '@/components/ui/alert'
7import { 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
18import { Alert } from '@/components/ui/alert'
19import { 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

shadcn/ui ships two Alert variants — default and destructive — and expects you to add more through the cva configuration if you need them. Drivn ships four out of the box: default, info, success, and destructive. Each variant comes with a color-tuned border, background tint, and text token that already matches the Drivn design tokens, so informational banners and success confirmations render without any extra work.

For applications that show multiple feedback states — a status banner at the top of a dashboard, a success confirmation after a form submit, a warning for a near-full quota — the extra two variants save a round of cva configuration per project. If you only ever render errors, the variant count is not decisive; if you build a product with mixed states, four defaults versus two saves a small but recurring amount of code. The feedback category shows how Alert, Toast, and Progress fit together for these cases.

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.

Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

npx drivn@latest create

Requires Node 18+. Works with npm, pnpm, and yarn.

Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

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.scss 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.