Flat props, not nested children.
One prop per slot. No more <CardHeader><CardTitle> ladders. Eighty percent of layouts ship with one tag.
Hand-stitched wrappers over shadcn/ui that swap nested children for flat props. Eighty percent of your UI ships with one tag. The other twenty — drop down to the primitive. No lock-in. No black box.
$ pnpm dlx shadcn@latest add @easy-shadcn/cardPaste into any shadcn-ready repo
A small library on purpose. Each component earns its way in by collapsing a recurring shadcn pattern into something you'd type without thinking.
The same card. Same behavior. Same primitive underneath. Pull once and watch the ladder fold flat.
Reduction: 13 → 7 lines · same primitives
Need the other 20%? Use the primitive →
We don't ship a component until it collapses a real pattern. If you've copy-pasted a shadcn structure three times this month, it belongs here.
ALine A
Content & layout
Items array in. Expandable panels out. No nested triple per row.
@easy-shadcn/accordion→Status banners with title, description and action. One tag.
@easy-shadcn/alert→src + fallback, plus a badge slot. Initials when the image 404s.
@easy-shadcn/avatar→Trail of items in. Auto current page and collapsing ellipsis out.
@easy-shadcn/breadcrumb→Flat slots for title, description, action and footer.
@easy-shadcn/card→Media, title, description and content. No compound scaffolding.
@easy-shadcn/empty→value in, bar out — null for indeterminate. Label included.
@easy-shadcn/progress→One nav tree, desktop offcanvas and mobile sheet — shell included.
@easy-shadcn/sidebar→Items array in. Tabs out. Heterogeneous? Use the primitive.
@easy-shadcn/tabs→Wrap an element, pass content. Its own provider — zero setup.
@easy-shadcn/tooltip→BLine B
Forms & input
Three-view month/year navigation. No more native dropdowns.
@easy-shadcn/calendar→A box and its label, in one tag. Disabled and all.
@easy-shadcn/checkbox→Items array in, checked values out. Per-item disabled included.
@easy-shadcn/checkbox-group→Single or multiple, radio, checkbox, or toggle — one value model.
@easy-shadcn/choice-group→Type to filter items, pick one. Custom filter and empty states.
@easy-shadcn/combobox→Single, multiple, range, inline-input — one component.
@easy-shadcn/date-picker→Label, control, description, error — correctly wired together.
@easy-shadcn/field→Start and end addons around an input. No flex gymnastics.
@easy-shadcn/input-group→One real input. Slots, groups, and separators generated.
@easy-shadcn/input-otp→Options array in. Wired-up radio rows out. Labels and a11y included.
@easy-shadcn/radio-group→Items, value, async search. The state machine, fully owned.
@easy-shadcn/select→A labeled slider with showValue. No markup per mark.
@easy-shadcn/slider→A labeled toggle. Checked state without ceremony.
@easy-shadcn/switch→CLine C
Overlays & dialogs
Confirm the dangerous thing. Async onConfirm, destructive variant.
@easy-shadcn/alert-dialog→Menu items as data — icons, shortcuts, destructive rows.
@easy-shadcn/dropdown-menu→Right-click target in. Flat actions at the pointer out.
@easy-shadcn/context-menu→Persistent nav from one tree. Selection, submenus, groups, keys.
@easy-shadcn/menu→Imperative alert & confirm, ready for command palettes.
@easy-shadcn/modal→Trigger and content, anchored. Placement without plumbing.
@easy-shadcn/popover→An edge panel with title, description, footer — pick a side.
@easy-shadcn/sheet→DLine D
Data & actions
Returns a Promise? It handles loading, icons and anti-flash.
@easy-shadcn/async-button→Client state or route links — two modes, never mixed.
@easy-shadcn/pagination→columns + dataSource + rowKey. Row selection with per-row control.
@easy-shadcn/table→The registry gives you components to copy. This one is a real npm package: an imperative modal manager whose promise settles with whatever the user decided.
const modal = useModal(ConfirmDialog)
// somewhere in a handler:
const ok = await modal.show({ orderId: "A-1042" })
if (ok) await archiveOrder(orderId)$ pnpm add @easy-shadcn/command-modalRead the docsOne prop per slot. No more <CardHeader><CardTitle> ladders. Eighty percent of layouts ship with one tag.
Compose layer never grows render props or slot objects. Need the other twenty? Drop down to components/ui/* — the door is unlocked.
Installed through the shadcn CLI. Every component lives inside your project, fully owned and trivially patched. No black box.
"Every prop is a debt. We pay it back by leaving the primitive unlocked — so the twenty percent of users who need more don't have to fight us for it."
$ pnpm dlx shadcn@latest add @easy-shadcn/cardOne command. The code lands in your repo.