🧩 shadcn-ui-react
A production-ready React UI library that packages shadcn/ui components into a single reusable library, with Tailwind CSS styling, Radix UI primitives, form helpers, and ready-to-use demos.
📦 Installation
npm install shadcn-ui-react
pnpm add shadcn-ui-react
yarn add shadcn-ui-react
Peer dependencies
npm install react react-dom
🚀 Getting started
1. Import the global styles
Import the package stylesheet once in your app entry file, layout, or root component.
import 'shadcn-ui-react/dist/style.css';
2. Use components
import { Button } from 'shadcn-ui-react';
export default function App() {
return (
<div className="flex gap-3 p-6">
<Button>Save</Button>
<Button variant="outline">Cancel</Button>
</div>
);
}
🧱 Available Components
📦 UI Primitives
Accordion
Alert
AlertDialog
Avatar
Badge
Breadcrumb
Button
IconButton
Calendar
Card
Carousel
Checkbox
Collapsible
Command
ContextMenu
Dialog
Drawer
DropdownMenu
HoverCard
Input
InputOtp
Label
Menubar
Modal
NavigationMenu
Pagination
Popover
Progress
RadioGroup
Resizable
ScrollArea
Select
Separator
Sheet
Skeleton
Slider
Sonner
Switch
Table
Tabs
Textarea
Toast
Toaster
Toggle
ToggleGroup
Tooltip
🧠 Forms
Form
FormField
FormSelect
FormCheckbox
FormItem
FormControl
FormLabel
FormDescription
FormMessage
UiInput
UiSelect
UiCheckbox
🧩 Shared Components
AlertModal
Breadcrumbs
DataTable
DataTableSkeleton
Dropzone
FileUpload
Heading
PageHead
PaginationSection
SearchInput
SearchableSelect
🛠️ Utilities
cn
useToast
toast
Icons
useSidebar
✨ Demos
1. Button
import { Button } from 'shadcn-ui-react';
export function ButtonDemo() {
return (
<div className="flex flex-wrap gap-3">
<Button>Default</Button>
<Button variant="outline">Outline</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Delete</Button>
<Button variant="soft">Soft</Button>
<Button variant="gradient">Gradient</Button>
<Button loading>Loading</Button>
</div>
);
}
2. IconButton
import { Pencil, Trash2 } from 'lucide-react';
import { IconButton } from 'shadcn-ui-react';
export function IconButtonDemo() {
return (
<div className="flex gap-2">
<IconButton aria-label="Edit item" variant="outline">
<Pencil />
</IconButton>
<IconButton aria-label="Delete item" variant="softDestructive">
<Trash2 />
</IconButton>
</div>
);
}
3. UiInput
import * as React from 'react';
import { UiInput } from 'shadcn-ui-react';
export function UiInputDemo() {
const [name, setName] = React.useState('');
return (
<UiInput
htmlFormItemId="name"
label="Name"
requiredLabel
placeholder="Enter your name"
value={name}
onChange={(event) => setName(event.target.value)}
errorMessage={
name.length > 0 && name.trim().length < 2
? 'Minimum 2 characters'
: undefined
}
/>
);
}
4. UiSelect
import * as React from 'react';
import { UiSelect } from 'shadcn-ui-react';
export function UiSelectDemo() {
const [language, setLanguage] = React.useState('');
return (
<UiSelect
htmlFormItemId="language"
label="Language"
placeholder="Select a language"
value={language}
onChange={setLanguage}
items={[
{ label: 'English', value: 'en' },
{ label: 'Spanish', value: 'es' },
{ label: 'Portuguese', value: 'pt' },
{ label: 'French', value: 'fr' },
{ label: 'Japanese', value: 'ja', disabled: true }
]}
errorMessage={!language ? 'Select a language.' : undefined}
/>
);
}
5. UiCheckbox
import * as React from 'react';
import { UiCheckbox } from 'shadcn-ui-react';
export function UiCheckboxDemo() {
const [accepted, setAccepted] = React.useState(false);
return (
<UiCheckbox
htmlFormItemId="terms"
checked={accepted}
onCheckedChange={(value) => setAccepted(value === true)}
label="I accept the terms and conditions"
description="You can change this option later from your account settings."
requiredLabel
errorMessage={!accepted ? 'You must accept the terms.' : undefined}
/>
);
}
6. React Hook Form + Zod
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import {
Button,
Form,
FormCheckbox,
FormField,
FormSelect
} from 'shadcn-ui-react';
const schema = z.object({
name: z.string().min(2, 'Minimum 2 characters'),
email: z.string().email('Invalid email address'),
password: z.string().min(8, 'Minimum 8 characters'),
role: z.enum(['owner', 'editor', 'viewer']),
accepted: z.boolean().refine(Boolean, 'You must accept the terms')
});
type FormValues = z.infer<typeof schema>;
export function FormDemo() {
const form = useForm<FormValues>({
resolver: zodResolver(schema),
defaultValues: {
name: '',
email: '',
password: '',
role: 'viewer',
accepted: false
}
});
const onSubmit = (values: FormValues) => {
console.log(values);
};
return (
<Form
methods={form}
onSubmit={onSubmit}
formProps={{ className: 'space-y-4' }}
>
<FormField
control={form.control}
name="name"
label="Name"
placeholder="Jane Doe"
requiredLabel
/>
<FormField
control={form.control}
name="email"
label="Email"
type="email"
placeholder="jane@example.com"
requiredLabel
/>
<FormField
control={form.control}
name="password"
label="Password"
type="password"
placeholder="••••••••"
requiredLabel
/>
<FormSelect
control={form.control}
name="role"
label="Role"
placeholder="Select a role"
items={[
{ label: 'Owner', value: 'owner' },
{ label: 'Editor', value: 'editor' },
{ label: 'Viewer', value: 'viewer' }
]}
/>
<FormCheckbox
control={form.control}
name="accepted"
label="I accept the terms"
description="This field is required to continue."
/>
<Button type="submit" className="w-full">
Create account
</Button>
</Form>
);
}
7. SearchableSelect standalone
import * as React from 'react';
import { SearchableSelect } from 'shadcn-ui-react';
export function SearchableSelectDemo() {
const [fruit, setFruit] = React.useState('');
return (
<SearchableSelect
value={fruit}
onValueChange={setFruit}
placeholder="Select a fruit"
searchPlaceholder="Search fruit..."
items={[
{ label: 'Apple', value: 'apple', keywords: 'fruit red green sweet' },
{ label: 'Banana', value: 'banana', keywords: 'fruit yellow tropical' },
{ label: 'Orange', value: 'orange', keywords: 'fruit citrus vitamin c' },
{
label: 'Strawberry',
value: 'strawberry',
keywords: 'fruit berry red sweet'
},
{
label: 'Pineapple',
value: 'pineapple',
keywords: 'fruit tropical sweet'
}
]}
/>
);
}
8. Accordion
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger
} from 'shadcn-ui-react';
export function AccordionDemo() {
return (
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="item-1">
<AccordionTrigger>What is included?</AccordionTrigger>
<AccordionContent>
Accessible components, Tailwind CSS styling, and reusable form helpers.
</AccordionContent>
</AccordionItem>
</Accordion>
);
}
9. Dialog
import {
Button,
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger
} from 'shadcn-ui-react';
export function DialogDemo() {
return (
<Dialog>
<DialogTrigger asChild>
<Button>Open dialog</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Create note</DialogTitle>
</DialogHeader>
<p className="text-sm text-muted-foreground">
Use this area for a form, message, or confirmation content.
</p>
</DialogContent>
</Dialog>
);
}
10. AlertModal
import * as React from 'react';
import { AlertModal, Button } from 'shadcn-ui-react';
export function AlertModalDemo() {
const [open, setOpen] = React.useState(false);
return (
<>
<Button variant="destructive" onClick={() => setOpen(true)}>
Delete item
</Button>
<AlertModal
isOpen={open}
onClose={() => setOpen(false)}
onConfirm={() => setOpen(false)}
loading={false}
/>
</>
);
}
11. DataTable
import * as React from 'react';
import type { ColumnDef } from '@tanstack/react-table';
import { DataTable } from 'shadcn-ui-react';
type Project = {
id: number;
name: string;
owner: string;
status: 'Active' | 'Paused' | 'Completed';
};
const columns: ColumnDef<Project>[] = [
{ accessorKey: 'id', header: 'ID' },
{ accessorKey: 'name', header: 'Project' },
{ accessorKey: 'owner', header: 'Owner' },
{ accessorKey: 'status', header: 'Status' }
];
const data: Project[] = [
{ id: 1, name: 'Website Redesign', owner: 'Jane Cooper', status: 'Active' },
{ id: 2, name: 'Mobile App', owner: 'Wade Warren', status: 'Paused' },
{ id: 3, name: 'Design System', owner: 'Esther Howard', status: 'Completed' }
];
export function DataTableDemo() {
const [page, setPage] = React.useState(1);
const [perPage, setPerPage] = React.useState(5);
const pageCount = Math.ceil(data.length / perPage);
const visibleRows = data.slice((page - 1) * perPage, page * perPage);
return (
<DataTable
columns={columns}
data={visibleRows}
page={page}
perPage={perPage}
pageCount={pageCount}
totalRows={data.length}
onPageChange={setPage}
onPageSizeChange={(size) => {
setPerPage(size);
setPage(1);
}}
template="neo"
accent="primary"
stickyHeader
animate
heightClassName="h-[420px]"
/>
);
}
12. SearchInput
import * as React from 'react';
import { SearchInput } from 'shadcn-ui-react';
export function SearchInputDemo() {
const [search, setSearch] = React.useState('');
return (
<SearchInput
value={search}
placeholder="Search documents..."
debounceTime={400}
onSearch={(value) => setSearch(value ?? '')}
/>
);
}
13. FileUpload / Dropzone
import { Dropzone } from 'shadcn-ui-react';
export function DropzoneDemo() {
return (
<Dropzone
onDrop={(files) => {
console.log(files);
}}
/>
);
}
14. Toast
import { Button, Toaster, useToast } from 'shadcn-ui-react';
export function ToastDemo() {
const { toast } = useToast();
return (
<>
<Button
onClick={() => {
toast({
title: 'Saved',
description: 'Your changes were saved successfully.'
});
}}
>
Show toast
</Button>
<Toaster />
</>
);
}
15. Sonner
import { toast } from 'sonner';
import { Button, Sonner } from 'shadcn-ui-react';
export function SonnerDemo() {
return (
<>
<Button onClick={() => toast.success('Operation completed')}>
Notify
</Button>
<Sonner />
</>
);
}
16. Card + Badge
import {
Badge,
Card,
CardContent,
CardHeader,
CardTitle
} from 'shadcn-ui-react';
export function CardDemo() {
return (
<Card className="max-w-md">
<CardHeader>
<CardTitle className="flex items-center justify-between gap-4">
Starter Kit
<Badge>New</Badge>
</CardTitle>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
A simple card example with a title, badge, and supporting description.
</CardContent>
</Card>
);
}
17. Tabs
import { Tabs, TabsContent, TabsList, TabsTrigger } from 'shadcn-ui-react';
export function TabsDemo() {
return (
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
</TabsList>
<TabsContent value="overview">General information goes here.</TabsContent>
<TabsContent value="settings">Preferences and configuration go here.</TabsContent>
</Tabs>
);
}
💅 Theming
This package uses Tailwind CSS variables. You can override the default theme from your app CSS.
:root {
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(64.12% 0.209 16.22);
--destructive-foreground: oklch(97.913% 0.00011 271.152);
--border: oklch(0.922 0 0);
--input: #fdfdfd;
--ring: 221.2 83.2% 53.3%;
--radius: 0.75rem;
}
📝 License
MIT.