Guide
Switching from shadcn
Ouro HX follows the shadcn/ui registry standard and reads the same theme variables, so switching is one component at a time, not a migration.
Both live in one app
shadcn/ui installs to components/ui/. Ouro HX installs to components/ouro/, so a shadcn button and an Ouro button never collide.beside Switch a screen at a time, and remove the shadcn file when nothing imports it any more.
Ouro components read shadcn's variables (--primary, --muted-foreground, --radius and the rest), so your theme carries over unchanged. Dark mode is the same .dark class. Ouro HX adds only what shadcn themes lack, in ouro-base.css: --success and --warning with their foregrounds, --destructive-foreground, the motion tokens, and --ouro-layer, the z-index of sheets and dialogs (50, as in the Base UI dialog of shadcn@4.21.1; raise it if your app has fixed bars above z-50).layer To change any --ouro-* token, such as --ouro-layer, --ouro-press-scale or --ouro-backdrop-max, set it in a :root (or .dark) rule of your own after the Ouro tokens, outside any @layer. Don't edit the lines shadcn wrote: every shadcn add of an Ouro item rewrites them. The Ouro look (ouro-theme) is optional; skip it to keep yours.
Components
Button- Ouro HX:
Button - Same name; the props differ (below).
DialogwithDialogTrigger,DialogContent,DialogHeader,DialogTitle,DialogDescription,DialogFooter- Ouro HX:
Dialogwithtrigger,title,descriptionandfooter - Becomes a bottom sheet below 640px.dialog-sheet Parts exist for layouts the props can't express.
SheetwithSheetTrigger,SheetContent,SheetHeader,SheetTitle- Ouro HX:
Sheetwithtrigger,sideandtitle - Dragged back to its edge to dismiss.
Drawer- Ouro HX:
SheetwithsnapPoints snapPoints={[0.5, 1]}opens at half height.AlertDialog- Ouro HX:
ConfirmDialog - Cancel has focus first; an outside press doesn't dismiss it.
- Classes on
<h1>to<h6> - Ouro HX:
Headingwithlevelandsize levelsets the tag;sizeonly the look.- Classes on
<p>(text-sm text-muted-foreground) - Ouro HX:
Textwithsizeandtone <Text size="sm" tone="muted">
Button props
variant="default"- Ouro HX: The default:
<Button> variant="destructive"- Ouro HX:
tone="destructive" variant="secondary"- Ouro HX:
tone="secondary" variant="outline"- Ouro HX:
variant="outline" tone="secondary" variant="ghost"- Ouro HX:
variant="plain", withtone="secondary"for foreground-colored text variant="link"- Ouro HX:
variant="plain"withhref size="default"- Ouro HX:
size="md", the default asChildaround a link- Ouro HX:
href, which renders a link (internal paths go throughOuroProvider'slinkComponent) disabledwhile saving- Ouro HX:
loading, which also shows a spinner and keeps focus - An icon as a child
- Ouro HX:
startIcon={Icon}orendIcon={Icon} className="w-full"- Ouro HX:
fullWidth - Appearance classes (
bg-red-500) - Ouro HX:
tone,variantandsize;classNameis for layout
Dialog and Sheet props
openandonOpenChange- Ouro HX: The same
<DialogTrigger asChild>around a button- Ouro HX:
trigger={<Button>Edit</Button>} <DialogTitle>- Ouro HX:
title, required (hideTitlehides it visually) <DialogDescription>- Ouro HX:
description <DialogFooter>- Ouro HX:
footer, primary action last <SheetContent side="right">- Ouro HX:
<Sheet side="right">
AlertDialog to ConfirmDialog
<AlertDialogTitle>- Ouro HX:
title, the question <AlertDialogDescription>- Ouro HX:
description <AlertDialogAction onClick={…}>Delete</AlertDialogAction>- Ouro HX:
confirmLabel="Delete"andonConfirm; return a promise to show progress <AlertDialogCancel>- Ouro HX:
cancelLabel,"Cancel"by default - A destructive class on the action
- Ouro HX:
tone="destructive"
If you miss one
Shadcn's prop names that Ouro HX doesn't use, and its Button variant and size values, fail the type check, and the error names the Ouro prop to use. In development, Button's console message names the fix for each guard prop and each shadcn variant and size:button-guards
Claim sources
- beside: scripts/install-test.sh; .github/workflows/ci.yml
verify:fileLine(scripts/install-test.sh, /Stock shadcn button beside Ouro's/)verify:ciJob(ci.yml#install) - layer: registry/ouro/theme/ouro-base.css; https://github.com/shadcn-ui/ui/blob/3502dbcde11d1eaf967a47ac375744dc336641f3/apps/v4/registry/bases/base/ui/dialog.tsx#L33-L53; scripts/install-test.sh
verify:fileLine(registry/ouro/theme/ouro-base.css, /--ouro-layer: 50;/)verify:urlOk(https://github.com/shadcn-ui/ui/blob/3502dbcde11d1eaf967a47ac375744dc336641f3/apps/v4/registry/bases/base/ui/dialog.tsx#L33-L53)verify:fileLine(scripts/install-test.sh, /grep -c 'z-50' src.components.ui.dialog.tsx/)verify:ciJob(ci.yml#install) - dialog-sheet: test:registry/ouro/components/ouro/dialog/dialog.test.tsx::automatic presentation > renders the bottom sheet at 390px; test:registry/ouro/components/ouro/dialog/dialog.test.tsx::automatic presentation > stays open in the new presentation when a resize crosses 640px, keeping controlled state
verify:testExists(registry/ouro/components/ouro/dialog/dialog.test.tsx::automatic presentation > renders the bottom sheet at 390px)verify:testExists(registry/ouro/components/ouro/dialog/dialog.test.tsx::automatic presentation > stays open in the new presentation when a resize crosses 640px, keeping controlled state)
<Button variant="destructive">Delete</Button>
[ouro-ui] Button: variant="destructive" is not a variant. Fix: <Button tone="destructive">.