Shadcn UI
Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
Links, Courses and Tutorials about Shadcn UI.
Get help with Shadcn UI from the community or creators.
npx shadcn-ui@latest init
We recommend that you leave all default options in the upcoming dialogue. You can now install Shadcn UI components to your project like so:
npx shadcn-ui@latest add button
This will add the Button component to your project, that you can use like so:
import { Button } from '@/components/ui/button'export default function Home() { return ( <div> <Button>Click me</Button> </div> )}
Theming
Copy Code
and insert the code into your globals.css
:
@layer base { :root { --background: 0 0% 100%; --foreground: 20 14.3% 4.1%; --card: 0 0% 100%; --card-foreground: 20 14.3% 4.1%; --popover: 0 0% 100%; --popover-foreground: 20 14.3% 4.1%; --primary: 24.6 95% 53.1%; --primary-foreground: 60 9.1% 97.8%; --secondary: 60 4.8% 95.9%; --secondary-foreground: 24 9.8% 10%; --muted: 60 4.8% 95.9%; --muted-foreground: 25 5.3% 44.7%; --accent: 60 4.8% 95.9%; --accent-foreground: 24 9.8% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 60 9.1% 97.8%; --border: 20 5.9% 90%; --input: 20 5.9% 90%; --ring: 24.6 95% 53.1%; --radius: 0.5rem; } .dark { --background: 20 14.3% 4.1%; --foreground: 60 9.1% 97.8%; --card: 20 14.3% 4.1%; --card-foreground: 60 9.1% 97.8%; --popover: 20 14.3% 4.1%; --popover-foreground: 60 9.1% 97.8%; --primary: 20.5 90.2% 48.2%; --primary-foreground: 60 9.1% 97.8%; --secondary: 12 6.5% 15.1%; --secondary-foreground: 60 9.1% 97.8%; --muted: 12 6.5% 15.1%; --muted-foreground: 24 5.4% 63.9%; --accent: 12 6.5% 15.1%; --accent-foreground: 60 9.1% 97.8%; --destructive: 0 72.2% 50.6%; --destructive-foreground: 60 9.1% 97.8%; --border: 12 6.5% 15.1%; --input: 12 6.5% 15.1%; --ring: 20.5 90.2% 48.2%; }}
Modal Auto focus
When opening a modal with Shadcn UI, focus is automatically trapped inside the first focusable input, like search bar.
This can be problematic on mobile devices, where the virtual keyboard may overlap with your content:
DialogContent
component in Shadcn UI's dialog:
const DialogContent = React.forwardRef< React.ElementRef<typeof DialogPrimitive.Content>, React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>>(({ className, children, ...props }, ref) => ( <DialogPortal> <DialogOverlay /> <DialogPrimitive.Content // ... other props onOpenAutoFocus={async (e) => { e.preventDefault() // prevent the auto focus behavior const { isMobile } = await import('react-device-detect') if (!e.target || isMobile) { return } // if it turns out we are not on mobile, we can focus the first focusable element const focusable = (e.target as HTMLElement).querySelectorAll( 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])' ) ;(focusable[0] as HTMLElement).focus() }} {...props} > {children} <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> <Cross2Icon className="h-4 w-4" /> <span className="sr-only">Close</span> </DialogPrimitive.Close> </DialogPrimitive.Content> </DialogPortal>))
If we try again on mobile now, we will see that it doesn't focus the search bar anymore:
On Desktop browsers without virtual keyboard it will keep focusing it.