diff --git a/apps/docs/app/api/demo/repos/route.ts b/apps/docs/app/api/demo/repos/route.ts
new file mode 100644
index 0000000..75fc101
--- /dev/null
+++ b/apps/docs/app/api/demo/repos/route.ts
@@ -0,0 +1,17 @@
+const items = [
+ { value: 'hareru-ui', label: 'hareru-ai/ui' },
+ { value: 'next-js', label: 'vercel/next.js' },
+ { value: 'react', label: 'facebook/react' },
+ { value: 'typescript', label: 'microsoft/typescript' },
+ { value: 'vite', label: 'vitejs/vite' },
+ { value: 'tailwindcss', label: 'tailwindlabs/tailwindcss' },
+ { value: 'biome', label: 'biomejs/biome' },
+ { value: 'vitest', label: 'vitest-dev/vitest' },
+];
+
+export function GET(req: Request) {
+ const url = new URL(req.url);
+ const q = (url.searchParams.get('q') ?? '').toLowerCase();
+ const filtered = q ? items.filter((i) => i.label.toLowerCase().includes(q)) : items;
+ return Response.json({ items: filtered });
+}
diff --git a/apps/docs/app/api/demo/search/route.ts b/apps/docs/app/api/demo/search/route.ts
new file mode 100644
index 0000000..b00ae70
--- /dev/null
+++ b/apps/docs/app/api/demo/search/route.ts
@@ -0,0 +1,19 @@
+const items = [
+ { value: 'apple', label: 'Apple' },
+ { value: 'banana', label: 'Banana' },
+ { value: 'cherry', label: 'Cherry' },
+ { value: 'grape', label: 'Grape' },
+ { value: 'lemon', label: 'Lemon' },
+ { value: 'mango', label: 'Mango' },
+ { value: 'orange', label: 'Orange' },
+ { value: 'peach', label: 'Peach' },
+ { value: 'strawberry', label: 'Strawberry' },
+ { value: 'watermelon', label: 'Watermelon' },
+];
+
+export function GET(req: Request) {
+ const url = new URL(req.url);
+ const q = (url.searchParams.get('q') ?? '').toLowerCase();
+ const filtered = q ? items.filter((i) => i.label.toLowerCase().includes(q)) : items;
+ return Response.json({ items: filtered });
+}
diff --git a/apps/docs/app/components/preview/ComponentPreview.tsx b/apps/docs/app/components/preview/ComponentPreview.tsx
index 8f965f1..4b12a19 100644
--- a/apps/docs/app/components/preview/ComponentPreview.tsx
+++ b/apps/docs/app/components/preview/ComponentPreview.tsx
@@ -1,5 +1,6 @@
'use client';
+import { Toaster, TooltipProvider } from '@hareru/ui';
import { Suspense } from 'react';
import { demos } from './demo-registry';
import './ComponentPreview.css';
@@ -21,9 +22,12 @@ export function ComponentPreview({ name }: ComponentPreviewProps) {
return (
- Loading preview...
}>
-
-
+
+ Loading preview... }>
+
+
+
+
);
diff --git a/apps/docs/app/components/preview/demo-registry.ts b/apps/docs/app/components/preview/demo-registry.ts
index 13b0b50..e49242d 100644
--- a/apps/docs/app/components/preview/demo-registry.ts
+++ b/apps/docs/app/components/preview/demo-registry.ts
@@ -1,10 +1,64 @@
import { type ComponentType, lazy } from 'react';
export const demos: Record = {
+ 'accordion-demo': lazy(() => import('./demos/accordion-demo')),
+ 'alert-demo': lazy(() => import('./demos/alert-demo')),
+ 'alert-dialog-demo': lazy(() => import('./demos/alert-dialog-demo')),
+ 'approval-card-demo': lazy(() => import('./demos/approval-card-demo')),
+ 'aspect-ratio-demo': lazy(() => import('./demos/aspect-ratio-demo')),
+ 'async-combobox-field-demo': lazy(() => import('./demos/async-combobox-field-demo')),
+ 'avatar-demo': lazy(() => import('./demos/avatar-demo')),
+ 'badge-demo': lazy(() => import('./demos/badge-demo')),
+ 'bento-grid-demo': lazy(() => import('./demos/bento-grid-demo')),
+ 'breadcrumb-demo': lazy(() => import('./demos/breadcrumb-demo')),
'button-variants': lazy(() => import('./demos/button-variants')),
'card-demo': lazy(() => import('./demos/card-demo')),
+ 'chat-composer-demo': lazy(() => import('./demos/chat-composer-demo')),
+ 'chat-container-demo': lazy(() => import('./demos/chat-container-demo')),
+ 'chat-message-demo': lazy(() => import('./demos/chat-message-demo')),
+ 'checkbox-demo': lazy(() => import('./demos/checkbox-demo')),
+ 'checkbox-group-demo': lazy(() => import('./demos/checkbox-group-demo')),
+ 'collapsible-demo': lazy(() => import('./demos/collapsible-demo')),
+ 'combobox-demo': lazy(() => import('./demos/combobox-demo')),
+ 'command-demo': lazy(() => import('./demos/command-demo')),
+ 'confidence-badge-demo': lazy(() => import('./demos/confidence-badge-demo')),
+ 'context-menu-demo': lazy(() => import('./demos/context-menu-demo')),
+ 'data-quality-indicator-demo': lazy(() => import('./demos/data-quality-indicator-demo')),
+ 'definition-browser-demo': lazy(() => import('./demos/definition-browser-demo')),
'dialog-demo': lazy(() => import('./demos/dialog-demo')),
+ 'dropdown-menu-demo': lazy(() => import('./demos/dropdown-menu-demo')),
+ 'empty-state-demo': lazy(() => import('./demos/empty-state-demo')),
+ 'field-diff-demo': lazy(() => import('./demos/field-diff-demo')),
+ 'form-field-demo': lazy(() => import('./demos/form-field-demo')),
'input-demo': lazy(() => import('./demos/input-demo')),
- 'badge-demo': lazy(() => import('./demos/badge-demo')),
+ 'key-value-list-demo': lazy(() => import('./demos/key-value-list-demo')),
+ 'label-demo': lazy(() => import('./demos/label-demo')),
+ 'metric-card-demo': lazy(() => import('./demos/metric-card-demo')),
+ 'navigation-menu-demo': lazy(() => import('./demos/navigation-menu-demo')),
+ 'pagination-demo': lazy(() => import('./demos/pagination-demo')),
+ 'popover-demo': lazy(() => import('./demos/popover-demo')),
+ 'preview-card-demo': lazy(() => import('./demos/preview-card-demo')),
+ 'progress-demo': lazy(() => import('./demos/progress-demo')),
+ 'query-feedback-demo': lazy(() => import('./demos/query-feedback-demo')),
+ 'radio-group-demo': lazy(() => import('./demos/radio-group-demo')),
+ 'readonly-field-demo': lazy(() => import('./demos/readonly-field-demo')),
+ 'reasoning-panel-demo': lazy(() => import('./demos/reasoning-panel-demo')),
+ 'scroll-area-demo': lazy(() => import('./demos/scroll-area-demo')),
+ 'select-demo': lazy(() => import('./demos/select-demo')),
+ 'semantic-suggest-demo': lazy(() => import('./demos/semantic-suggest-demo')),
+ 'separator-demo': lazy(() => import('./demos/separator-demo')),
+ 'sheet-demo': lazy(() => import('./demos/sheet-demo')),
+ 'skeleton-demo': lazy(() => import('./demos/skeleton-demo')),
+ 'slider-demo': lazy(() => import('./demos/slider-demo')),
+ 'streaming-text-demo': lazy(() => import('./demos/streaming-text-demo')),
+ 'switch-demo': lazy(() => import('./demos/switch-demo')),
+ 'table-demo': lazy(() => import('./demos/table-demo')),
'tabs-demo': lazy(() => import('./demos/tabs-demo')),
+ 'textarea-demo': lazy(() => import('./demos/textarea-demo')),
+ 'toast-demo': lazy(() => import('./demos/toast-demo')),
+ 'toggle-demo': lazy(() => import('./demos/toggle-demo')),
+ 'toggle-group-demo': lazy(() => import('./demos/toggle-group-demo')),
+ 'tool-call-card-demo': lazy(() => import('./demos/tool-call-card-demo')),
+ 'toolbar-demo': lazy(() => import('./demos/toolbar-demo')),
+ 'tooltip-demo': lazy(() => import('./demos/tooltip-demo')),
};
diff --git a/apps/docs/app/components/preview/demos/accordion-demo.tsx b/apps/docs/app/components/preview/demos/accordion-demo.tsx
new file mode 100644
index 0000000..e3a0be0
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/accordion-demo.tsx
@@ -0,0 +1,43 @@
+'use client';
+
+import {
+ Accordion,
+ AccordionContent,
+ AccordionHeader,
+ AccordionItem,
+ AccordionTrigger,
+} from '@hareru/ui';
+
+export default function AccordionDemo() {
+ return (
+
+
+
+ What is Hareru UI?
+
+
+ Hareru UI is a semantic CSS design system with accessible React components built on Base
+ UI.
+
+
+
+
+ Is it accessible?
+
+
+ Yes. All interactive components follow WAI-ARIA guidelines and support keyboard
+ navigation.
+
+
+
+
+ Can I customize the styles?
+
+
+ Yes. Components expose CSS custom properties under the --hui- prefix for full
+ theming control.
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/alert-demo.tsx b/apps/docs/app/components/preview/demos/alert-demo.tsx
new file mode 100644
index 0000000..1fb64cd
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/alert-demo.tsx
@@ -0,0 +1,30 @@
+'use client';
+
+import { Alert, AlertDescription, AlertTitle } from '@hareru/ui';
+
+export default function AlertDemo() {
+ return (
+
+
+ Heads up!
+
+ You can add components and dependencies to your app using the CLI.
+
+
+
+ Error
+
+ Your session has expired. Please log in again to continue.
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/alert-dialog-demo.tsx b/apps/docs/app/components/preview/demos/alert-dialog-demo.tsx
new file mode 100644
index 0000000..fd4ebdd
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/alert-dialog-demo.tsx
@@ -0,0 +1,34 @@
+'use client';
+
+import {
+ AlertDialog,
+ AlertDialogAction,
+ AlertDialogCancel,
+ AlertDialogContent,
+ AlertDialogDescription,
+ AlertDialogFooter,
+ AlertDialogHeader,
+ AlertDialogTitle,
+ AlertDialogTrigger,
+} from '@hareru/ui';
+
+export default function AlertDialogDemo() {
+ return (
+
+ Delete account
+
+
+ Are you absolutely sure?
+
+ This action cannot be undone. This will permanently delete your account and remove your
+ data from our servers.
+
+
+
+ Cancel
+ Continue
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/approval-card-demo.tsx b/apps/docs/app/components/preview/demos/approval-card-demo.tsx
new file mode 100644
index 0000000..bd6b373
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/approval-card-demo.tsx
@@ -0,0 +1,30 @@
+'use client';
+
+import { ApprovalCard } from '@hareru/ui';
+
+export default function ApprovalCardDemo() {
+ return (
+
+
{}}
+ onReject={() => {}}
+ />
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/aspect-ratio-demo.tsx b/apps/docs/app/components/preview/demos/aspect-ratio-demo.tsx
new file mode 100644
index 0000000..0134939
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/aspect-ratio-demo.tsx
@@ -0,0 +1,26 @@
+'use client';
+
+import { AspectRatio } from '@hareru/ui';
+
+export default function AspectRatioDemo() {
+ return (
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/async-combobox-field-demo.tsx b/apps/docs/app/components/preview/demos/async-combobox-field-demo.tsx
new file mode 100644
index 0000000..9955e80
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/async-combobox-field-demo.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { AsyncComboboxField } from '@hareru/ui';
+
+export default function AsyncComboboxFieldDemo() {
+ return (
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/avatar-demo.tsx b/apps/docs/app/components/preview/demos/avatar-demo.tsx
new file mode 100644
index 0000000..038478f
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/avatar-demo.tsx
@@ -0,0 +1,21 @@
+'use client';
+
+import { Avatar, AvatarFallback, AvatarImage } from '@hareru/ui';
+
+export default function AvatarDemo() {
+ return (
+
+
+
+ SC
+
+
+
+ VC
+
+
+ JD
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/bento-grid-demo.tsx b/apps/docs/app/components/preview/demos/bento-grid-demo.tsx
new file mode 100644
index 0000000..76b04d4
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/bento-grid-demo.tsx
@@ -0,0 +1,60 @@
+'use client';
+
+import { BentoGrid, BentoGridItem } from '@hareru/ui';
+
+const layouts = {
+ lg: [
+ { i: 'a', x: 0, y: 0, w: 6, h: 2 },
+ { i: 'b', x: 6, y: 0, w: 6, h: 2 },
+ { i: 'c', x: 0, y: 2, w: 4, h: 2 },
+ { i: 'd', x: 4, y: 2, w: 8, h: 2 },
+ ],
+ sm: [
+ { i: 'a', x: 0, y: 0, w: 2, h: 2 },
+ { i: 'b', x: 2, y: 0, w: 2, h: 2 },
+ { i: 'c', x: 0, y: 2, w: 2, h: 2 },
+ { i: 'd', x: 2, y: 2, w: 2, h: 2 },
+ ],
+};
+
+const items = [
+ { key: 'a', label: 'Card A' },
+ { key: 'b', label: 'Card B' },
+ { key: 'c', label: 'Card C' },
+ { key: 'd', label: 'Card D' },
+];
+
+export default function BentoGridDemo() {
+ return (
+
+
+ {items.map((item) => (
+
+
+ {item.label}
+
+
+ ))}
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/breadcrumb-demo.tsx b/apps/docs/app/components/preview/demos/breadcrumb-demo.tsx
new file mode 100644
index 0000000..ec828d3
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/breadcrumb-demo.tsx
@@ -0,0 +1,30 @@
+'use client';
+
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from '@hareru/ui';
+
+export default function BreadcrumbDemo() {
+ return (
+
+
+
+ Home
+
+
+
+ Components
+
+
+
+ Breadcrumb
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/chat-composer-demo.tsx b/apps/docs/app/components/preview/demos/chat-composer-demo.tsx
new file mode 100644
index 0000000..83d10fc
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/chat-composer-demo.tsx
@@ -0,0 +1,16 @@
+'use client';
+
+import { ChatComposer, ChatComposerActions, ChatComposerInput, ChatComposerSend } from '@hareru/ui';
+
+export default function ChatComposerDemo() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/chat-container-demo.tsx b/apps/docs/app/components/preview/demos/chat-container-demo.tsx
new file mode 100644
index 0000000..05b2720
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/chat-container-demo.tsx
@@ -0,0 +1,36 @@
+'use client';
+
+import {
+ ChatContainer,
+ ChatContainerFooter,
+ ChatContainerHeader,
+ ChatContainerMessages,
+ ChatMessage,
+ ChatMessageContent,
+} from '@hareru/ui';
+
+export default function ChatContainerDemo() {
+ return (
+
+
+
+ Assistant
+
+
+
+ How do I reset my password?
+
+
+
+ You can reset your password from the account settings page. Click "Forgot password" on
+ the login screen.
+
+
+
+
+ Type a message...
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/chat-message-demo.tsx b/apps/docs/app/components/preview/demos/chat-message-demo.tsx
new file mode 100644
index 0000000..169e40a
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/chat-message-demo.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { ChatMessage, ChatMessageContent } from '@hareru/ui';
+
+export default function ChatMessageDemo() {
+ return (
+
+
+ Can you summarize the quarterly report?
+
+
+
+ The Q3 report shows a 12% revenue increase year-over-year, with strong performance in the
+ enterprise segment.
+
+
+
+ Conversation started
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/checkbox-demo.tsx b/apps/docs/app/components/preview/demos/checkbox-demo.tsx
new file mode 100644
index 0000000..3fd558b
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/checkbox-demo.tsx
@@ -0,0 +1,29 @@
+'use client';
+
+import { Checkbox, Label } from '@hareru/ui';
+import { useState } from 'react';
+
+export default function CheckboxDemo() {
+ const [checked, setChecked] = useState(false);
+
+ return (
+
+
+
+ Accept terms and conditions
+
+
+
+ Subscribe to newsletter
+
+
+
+ Indeterminate state
+
+
+
+ Disabled (checked)
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/checkbox-group-demo.tsx b/apps/docs/app/components/preview/demos/checkbox-group-demo.tsx
new file mode 100644
index 0000000..59f634f
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/checkbox-group-demo.tsx
@@ -0,0 +1,26 @@
+'use client';
+
+import { Checkbox, CheckboxGroup, Label } from '@hareru/ui';
+
+export default function CheckboxGroupDemo() {
+ return (
+
+
+
+
+
+ React
+
+
+
+ TypeScript
+
+
+
+ Vite
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/collapsible-demo.tsx b/apps/docs/app/components/preview/demos/collapsible-demo.tsx
new file mode 100644
index 0000000..4151575
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/collapsible-demo.tsx
@@ -0,0 +1,63 @@
+'use client';
+
+import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@hareru/ui';
+import { useState } from 'react';
+
+export default function CollapsibleDemo() {
+ const [open, setOpen] = useState(false);
+
+ return (
+
+
+ Keyboard shortcuts
+
+ {open ? 'Hide' : 'Show'}
+
+
+
+ ⌘ K — Open command palette
+
+
+
+
+ ⌘ B — Toggle sidebar
+
+
+ ⌘ S — Save file
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/combobox-demo.tsx b/apps/docs/app/components/preview/demos/combobox-demo.tsx
new file mode 100644
index 0000000..5ccd6fb
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/combobox-demo.tsx
@@ -0,0 +1,46 @@
+'use client';
+
+import {
+ Combobox,
+ ComboboxContent,
+ ComboboxEmpty,
+ ComboboxInput,
+ ComboboxItem,
+ ComboboxList,
+ ComboboxTrigger,
+} from '@hareru/ui';
+import { useState } from 'react';
+
+const fruits = [
+ { value: 'apple', label: 'Apple' },
+ { value: 'banana', label: 'Banana' },
+ { value: 'cherry', label: 'Cherry' },
+ { value: 'grape', label: 'Grape' },
+ { value: 'mango', label: 'Mango' },
+ { value: 'orange', label: 'Orange' },
+];
+
+export default function ComboboxDemo() {
+ const [selected, setSelected] = useState('');
+
+ return (
+
+ {selected || 'Select a fruit...'}
+
+
+
+ No fruit found.
+ {fruits.map((fruit) => (
+ setSelected(fruit.label)}
+ >
+ {fruit.label}
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/command-demo.tsx b/apps/docs/app/components/preview/demos/command-demo.tsx
new file mode 100644
index 0000000..ddd8baa
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/command-demo.tsx
@@ -0,0 +1,33 @@
+'use client';
+
+import {
+ Command,
+ CommandEmpty,
+ CommandGroup,
+ CommandInput,
+ CommandItem,
+ CommandList,
+} from '@hareru/ui';
+
+export default function CommandDemo() {
+ return (
+
+
+
+ No results found.
+
+ Calendar
+ Search emoji
+ Calculator
+ Launch settings
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/confidence-badge-demo.tsx b/apps/docs/app/components/preview/demos/confidence-badge-demo.tsx
new file mode 100644
index 0000000..264027d
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/confidence-badge-demo.tsx
@@ -0,0 +1,21 @@
+'use client';
+
+import { ConfidenceBadge } from '@hareru/ui';
+
+export default function ConfidenceBadgeDemo() {
+ return (
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/context-menu-demo.tsx b/apps/docs/app/components/preview/demos/context-menu-demo.tsx
new file mode 100644
index 0000000..ff2a779
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/context-menu-demo.tsx
@@ -0,0 +1,41 @@
+'use client';
+
+import {
+ ContextMenu,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuTrigger,
+} from '@hareru/ui';
+
+export default function ContextMenuDemo() {
+ return (
+
+
+
+ Right-click here
+
+
+
+ Back
+ Forward
+ Reload
+
+ View Page Source
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/data-quality-indicator-demo.tsx b/apps/docs/app/components/preview/demos/data-quality-indicator-demo.tsx
new file mode 100644
index 0000000..5d2d5ad
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/data-quality-indicator-demo.tsx
@@ -0,0 +1,28 @@
+'use client';
+
+import { DataQualityIndicator } from '@hareru/ui';
+
+export default function DataQualityIndicatorDemo() {
+ return (
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/definition-browser-demo.tsx b/apps/docs/app/components/preview/demos/definition-browser-demo.tsx
new file mode 100644
index 0000000..0e2a1f4
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/definition-browser-demo.tsx
@@ -0,0 +1,51 @@
+'use client';
+
+import { DefinitionBrowser } from '@hareru/ui';
+
+export default function DefinitionBrowserDemo() {
+ return (
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/dropdown-menu-demo.tsx b/apps/docs/app/components/preview/demos/dropdown-menu-demo.tsx
new file mode 100644
index 0000000..42defe2
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/dropdown-menu-demo.tsx
@@ -0,0 +1,30 @@
+'use client';
+
+import {
+ Button,
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ DropdownMenuTrigger,
+} from '@hareru/ui';
+
+export default function DropdownMenuDemo() {
+ return (
+
+
+ Open menu
+
+
+ My Account
+
+ Profile
+ Billing
+ Settings
+
+ Log out
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/empty-state-demo.tsx b/apps/docs/app/components/preview/demos/empty-state-demo.tsx
new file mode 100644
index 0000000..0cf8903
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/empty-state-demo.tsx
@@ -0,0 +1,23 @@
+'use client';
+
+import {
+ Button,
+ EmptyState,
+ EmptyStateAction,
+ EmptyStateDescription,
+ EmptyStateTitle,
+} from '@hareru/ui';
+
+export default function EmptyStateDemo() {
+ return (
+
+ No results found
+
+ Try adjusting your search or filter to find what you are looking for.
+
+
+ Clear filters
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/field-diff-demo.tsx b/apps/docs/app/components/preview/demos/field-diff-demo.tsx
new file mode 100644
index 0000000..2f3b32d
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/field-diff-demo.tsx
@@ -0,0 +1,16 @@
+'use client';
+
+import { FieldDiff } from '@hareru/ui';
+
+export default function FieldDiffDemo() {
+ return (
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/form-field-demo.tsx b/apps/docs/app/components/preview/demos/form-field-demo.tsx
new file mode 100644
index 0000000..0ac5299
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/form-field-demo.tsx
@@ -0,0 +1,33 @@
+'use client';
+
+import {
+ FormField,
+ FormFieldControl,
+ FormFieldDescription,
+ FormFieldLabel,
+ FormFieldMessage,
+ Input,
+} from '@hareru/ui';
+
+export default function FormFieldDemo() {
+ return (
+
+
+ Username
+
+
+
+ This is your public display name.
+
+
+
+ Email
+
+
+
+ We will never share your email.
+ Please enter a valid email address.
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/key-value-list-demo.tsx b/apps/docs/app/components/preview/demos/key-value-list-demo.tsx
new file mode 100644
index 0000000..e0c724f
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/key-value-list-demo.tsx
@@ -0,0 +1,17 @@
+'use client';
+
+import { KeyValueList } from '@hareru/ui';
+
+export default function KeyValueListDemo() {
+ return (
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/label-demo.tsx b/apps/docs/app/components/preview/demos/label-demo.tsx
new file mode 100644
index 0000000..0663735
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/label-demo.tsx
@@ -0,0 +1,18 @@
+'use client';
+
+import { Input, Label } from '@hareru/ui';
+
+export default function LabelDemo() {
+ return (
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/metric-card-demo.tsx b/apps/docs/app/components/preview/demos/metric-card-demo.tsx
new file mode 100644
index 0000000..21f2b7f
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/metric-card-demo.tsx
@@ -0,0 +1,43 @@
+'use client';
+
+import { MetricCard } from '@hareru/ui';
+
+export default function MetricCardDemo() {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/navigation-menu-demo.tsx b/apps/docs/app/components/preview/demos/navigation-menu-demo.tsx
new file mode 100644
index 0000000..4be9b8c
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/navigation-menu-demo.tsx
@@ -0,0 +1,73 @@
+'use client';
+
+import {
+ NavigationMenu,
+ NavigationMenuContent,
+ NavigationMenuItem,
+ NavigationMenuLink,
+ NavigationMenuList,
+ NavigationMenuTrigger,
+} from '@hareru/ui';
+
+export default function NavigationMenuDemo() {
+ return (
+
+
+
+ Getting started
+
+
+
+ Introduction
+
+ Overview of Hareru UI and its design principles.
+
+
+
+ Installation
+
+ How to install and set up in your project.
+
+
+
+
+
+
+ Components
+
+
+
+ Button
+
+ Triggers an action or event.
+
+
+
+ Input
+
+ Accepts text input from the user.
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/pagination-demo.tsx b/apps/docs/app/components/preview/demos/pagination-demo.tsx
new file mode 100644
index 0000000..08be73a
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/pagination-demo.tsx
@@ -0,0 +1,40 @@
+'use client';
+
+import {
+ Pagination,
+ PaginationContent,
+ PaginationEllipsis,
+ PaginationItem,
+ PaginationLink,
+ PaginationNext,
+ PaginationPrevious,
+} from '@hareru/ui';
+
+export default function PaginationDemo() {
+ return (
+
+
+
+ Previous
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+
+
+ Next
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/popover-demo.tsx b/apps/docs/app/components/preview/demos/popover-demo.tsx
new file mode 100644
index 0000000..5e93c11
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/popover-demo.tsx
@@ -0,0 +1,21 @@
+'use client';
+
+import { Button, Popover, PopoverContent, PopoverTrigger } from '@hareru/ui';
+
+export default function PopoverDemo() {
+ return (
+
+
+ Open popover
+
+
+
+
Dimensions
+
+ Set the dimensions for the layer.
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/preview-card-demo.tsx b/apps/docs/app/components/preview/demos/preview-card-demo.tsx
new file mode 100644
index 0000000..32a9446
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/preview-card-demo.tsx
@@ -0,0 +1,21 @@
+'use client';
+
+import { PreviewCard, PreviewCardContent, PreviewCardTrigger } from '@hareru/ui';
+
+export default function PreviewCardDemo() {
+ return (
+
+
+ @hareru/ui
+
+
+
+
Hareru UI
+
+ A semantic CSS design system with accessible React components.
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/progress-demo.tsx b/apps/docs/app/components/preview/demos/progress-demo.tsx
new file mode 100644
index 0000000..ea277be
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/progress-demo.tsx
@@ -0,0 +1,21 @@
+'use client';
+
+import { Progress } from '@hareru/ui';
+
+export default function ProgressDemo() {
+ return (
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/query-feedback-demo.tsx b/apps/docs/app/components/preview/demos/query-feedback-demo.tsx
new file mode 100644
index 0000000..aed1f50
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/query-feedback-demo.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { QueryFeedback } from '@hareru/ui';
+
+export default function QueryFeedbackDemo() {
+ return (
+
+
+ Was this response helpful?
+ console.log('feedback:', v)} />
+
+
+ Pre-selected helpful:
+
+
+
+ Disabled:
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/radio-group-demo.tsx b/apps/docs/app/components/preview/demos/radio-group-demo.tsx
new file mode 100644
index 0000000..a55699f
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/radio-group-demo.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { RadioGroup, RadioGroupItem } from '@hareru/ui';
+import { useState } from 'react';
+
+export default function RadioGroupDemo() {
+ const [value, setValue] = useState('standard');
+
+ return (
+
+
+ Free
+ Standard
+ Pro
+
+ Enterprise (contact sales)
+
+
+
Selected: {value}
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/readonly-field-demo.tsx b/apps/docs/app/components/preview/demos/readonly-field-demo.tsx
new file mode 100644
index 0000000..7dbeda8
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/readonly-field-demo.tsx
@@ -0,0 +1,13 @@
+'use client';
+
+import { ReadonlyField } from '@hareru/ui';
+
+export default function ReadonlyFieldDemo() {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/reasoning-panel-demo.tsx b/apps/docs/app/components/preview/demos/reasoning-panel-demo.tsx
new file mode 100644
index 0000000..28bec34
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/reasoning-panel-demo.tsx
@@ -0,0 +1,20 @@
+'use client';
+
+import { ReasoningPanel } from '@hareru/ui';
+
+export default function ReasoningPanelDemo() {
+ return (
+
+
+
+ The user is asking about revenue trends. I should query the orders dataset filtered by
+ date range and aggregate by month.
+
+ Joining with the products table will allow breakdown by category.
+
+
+ Analyzing the semantic model to identify relevant metrics...
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/scroll-area-demo.tsx b/apps/docs/app/components/preview/demos/scroll-area-demo.tsx
new file mode 100644
index 0000000..301d310
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/scroll-area-demo.tsx
@@ -0,0 +1,33 @@
+'use client';
+
+import { ScrollArea } from '@hareru/ui';
+
+const items = Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`);
+
+export default function ScrollAreaDemo() {
+ return (
+
+
+ {items.map((item) => (
+
+ {item}
+
+ ))}
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/select-demo.tsx b/apps/docs/app/components/preview/demos/select-demo.tsx
new file mode 100644
index 0000000..185319e
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/select-demo.tsx
@@ -0,0 +1,40 @@
+'use client';
+
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@hareru/ui';
+
+export default function SelectDemo() {
+ return (
+
+
+
+
+
+
+ Apple
+ Banana
+ Cherry
+
+
+
+
+
+
+
+
+ Apple
+ Banana
+ Cherry
+
+
+
+
+
+
+
+
+ Apple
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/semantic-suggest-demo.tsx b/apps/docs/app/components/preview/demos/semantic-suggest-demo.tsx
new file mode 100644
index 0000000..5efbd40
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/semantic-suggest-demo.tsx
@@ -0,0 +1,32 @@
+'use client';
+
+import { SemanticSuggest } from '@hareru/ui';
+
+export default function SemanticSuggestDemo() {
+ return (
+
+ {}}
+ onReject={() => {}}
+ />
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/separator-demo.tsx b/apps/docs/app/components/preview/demos/separator-demo.tsx
new file mode 100644
index 0000000..3496790
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/separator-demo.tsx
@@ -0,0 +1,29 @@
+'use client';
+
+import { Separator } from '@hareru/ui';
+
+export default function SeparatorDemo() {
+ return (
+
+
+
Above the separator
+
+
Below the separator
+
+
+ Blog
+
+ Docs
+
+ Source
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/sheet-demo.tsx b/apps/docs/app/components/preview/demos/sheet-demo.tsx
new file mode 100644
index 0000000..94a1f70
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/sheet-demo.tsx
@@ -0,0 +1,38 @@
+'use client';
+
+import {
+ Button,
+ Sheet,
+ SheetContent,
+ SheetDescription,
+ SheetHeader,
+ SheetTitle,
+ SheetTrigger,
+} from '@hareru/ui';
+
+export default function SheetDemo() {
+ return (
+
+
+ Open sheet
+
+
+
+ Edit profile
+
+ Make changes to your profile here. Click save when you are done.
+
+
+
+ Profile form fields would go here.
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/skeleton-demo.tsx b/apps/docs/app/components/preview/demos/skeleton-demo.tsx
new file mode 100644
index 0000000..5d21212
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/skeleton-demo.tsx
@@ -0,0 +1,33 @@
+'use client';
+
+import { Skeleton } from '@hareru/ui';
+
+export default function SkeletonDemo() {
+ return (
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/slider-demo.tsx b/apps/docs/app/components/preview/demos/slider-demo.tsx
new file mode 100644
index 0000000..38cc8bd
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/slider-demo.tsx
@@ -0,0 +1,45 @@
+'use client';
+
+import { Slider, SliderRange, SliderThumb, SliderTrack } from '@hareru/ui';
+import { useState } from 'react';
+
+export default function SliderDemo() {
+ const [value, setValue] = useState(40);
+
+ return (
+
+
+
+ Volume
+ {value}%
+
+
setValue(v as number)} min={0} max={100}>
+
+
+
+
+
+
+
+
+ Default value
+
+
+
+
+
+
+
+
+
+ Disabled
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/streaming-text-demo.tsx b/apps/docs/app/components/preview/demos/streaming-text-demo.tsx
new file mode 100644
index 0000000..1b56203
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/streaming-text-demo.tsx
@@ -0,0 +1,34 @@
+'use client';
+
+import { StreamingText } from '@hareru/ui';
+
+export default function StreamingTextDemo() {
+ return (
+
+
+
+ Completed (streaming=false)
+
+
+ The analysis is complete. All metrics are within expected ranges.
+
+
+
+
+ Streaming with blink cursor
+
+
+ Generating response
+
+
+
+
+ Streaming with pulse cursor
+
+
+ Loading data
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/switch-demo.tsx b/apps/docs/app/components/preview/demos/switch-demo.tsx
new file mode 100644
index 0000000..d4004c6
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/switch-demo.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { Label, Switch } from '@hareru/ui';
+
+export default function SwitchDemo() {
+ return (
+
+
+
+ Notifications
+
+
+
+ Marketing emails
+
+
+
+ Disabled (on)
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/table-demo.tsx b/apps/docs/app/components/preview/demos/table-demo.tsx
new file mode 100644
index 0000000..4fd2505
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/table-demo.tsx
@@ -0,0 +1,34 @@
+'use client';
+
+import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@hareru/ui';
+
+export default function TableDemo() {
+ return (
+
+
+
+ Name
+ Status
+ Amount
+
+
+
+
+ Alice Johnson
+ Active
+ $1,200
+
+
+ Bob Smith
+ Pending
+ $840
+
+
+ Carol White
+ Inactive
+ $2,450
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/textarea-demo.tsx b/apps/docs/app/components/preview/demos/textarea-demo.tsx
new file mode 100644
index 0000000..7106cdb
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/textarea-demo.tsx
@@ -0,0 +1,13 @@
+'use client';
+
+import { Textarea } from '@hareru/ui';
+
+export default function TextareaDemo() {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/toast-demo.tsx b/apps/docs/app/components/preview/demos/toast-demo.tsx
new file mode 100644
index 0000000..421152c
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/toast-demo.tsx
@@ -0,0 +1,33 @@
+'use client';
+
+import { Button, toast } from '@hareru/ui';
+
+export default function ToastDemo() {
+ return (
+
+
+ toast({
+ title: 'Scheduled',
+ description: 'Your meeting has been scheduled for tomorrow.',
+ })
+ }
+ >
+ Show toast
+
+
+ toast({
+ title: 'Something went wrong',
+ description: 'Please try again later.',
+ variant: 'destructive',
+ })
+ }
+ >
+ Show destructive
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/toggle-demo.tsx b/apps/docs/app/components/preview/demos/toggle-demo.tsx
new file mode 100644
index 0000000..05eaeb0
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/toggle-demo.tsx
@@ -0,0 +1,19 @@
+'use client';
+
+import { Toggle } from '@hareru/ui';
+
+export default function ToggleDemo() {
+ return (
+
+ Default
+ Pressed
+ Outline
+
+ Outline Pressed
+
+ Small
+ Large
+ Disabled
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/toggle-group-demo.tsx b/apps/docs/app/components/preview/demos/toggle-group-demo.tsx
new file mode 100644
index 0000000..9f0930d
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/toggle-group-demo.tsx
@@ -0,0 +1,39 @@
+'use client';
+
+import { ToggleGroup, ToggleGroupItem } from '@hareru/ui';
+
+export default function ToggleGroupDemo() {
+ return (
+
+
+ Left
+ Center
+ Right
+
+
+
+
+ Bold
+
+
+ Italic
+
+
+ Underline
+
+
+
+
+
+ S
+
+
+ M
+
+
+ L
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/tool-call-card-demo.tsx b/apps/docs/app/components/preview/demos/tool-call-card-demo.tsx
new file mode 100644
index 0000000..b72ff58
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/tool-call-card-demo.tsx
@@ -0,0 +1,24 @@
+'use client';
+
+import { ToolCallCard } from '@hareru/ui';
+
+export default function ToolCallCardDemo() {
+ return (
+
+
+
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/toolbar-demo.tsx b/apps/docs/app/components/preview/demos/toolbar-demo.tsx
new file mode 100644
index 0000000..974abdc
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/toolbar-demo.tsx
@@ -0,0 +1,26 @@
+'use client';
+
+import { Toolbar, ToolbarButton, ToolbarLink, ToolbarSeparator } from '@hareru/ui';
+
+export default function ToolbarDemo() {
+ return (
+
+
+ New
+ Open
+ Save
+
+ Preview
+
+ Docs
+
+
+
+ Undo
+ Redo
+
+ Export
+
+
+ );
+}
diff --git a/apps/docs/app/components/preview/demos/tooltip-demo.tsx b/apps/docs/app/components/preview/demos/tooltip-demo.tsx
new file mode 100644
index 0000000..ad2951f
--- /dev/null
+++ b/apps/docs/app/components/preview/demos/tooltip-demo.tsx
@@ -0,0 +1,26 @@
+'use client';
+
+import { Button, Tooltip, TooltipContent, TooltipTrigger } from '@hareru/ui';
+
+export default function TooltipDemo() {
+ return (
+
+
+
+ Hover me
+
+
+ Add to library
+
+
+
+
+ Top tooltip
+
+
+ Opens on top
+
+
+
+ );
+}
diff --git a/apps/docs/content/docs/components/accordion.mdx b/apps/docs/content/docs/components/accordion.mdx
index ad86c3e..a4ec559 100644
--- a/apps/docs/content/docs/components/accordion.mdx
+++ b/apps/docs/content/docs/components/accordion.mdx
@@ -7,6 +7,44 @@ description: Vertically stacked set of interactive headings that each reveal a s
**Dependency:** `@base-ui-components/react/accordion`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Accordion,
+ AccordionItem,
+ AccordionHeader,
+ AccordionTrigger,
+ AccordionContent,
+ } from "@hareru/ui"
+
+
+
+
+ What is Hareru UI?
+
+
+ A semantic design system built for agents.
+
+
+
+
+ How do I install it?
+
+
+ Run npm install @hareru/tokens @hareru/ui.
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/alert-dialog.mdx b/apps/docs/content/docs/components/alert-dialog.mdx
index 06772c3..d23f63b 100644
--- a/apps/docs/content/docs/components/alert-dialog.mdx
+++ b/apps/docs/content/docs/components/alert-dialog.mdx
@@ -7,6 +7,43 @@ description: Accessible confirmation dialog that requires an explicit user actio
**Dependency:** `@base-ui-components/react/alert-dialog`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ AlertDialog,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+ } from "@hareru/ui"
+
+
+ Delete account
+
+
+ Are you sure?
+ This action cannot be undone.
+
+
+ Cancel
+ Delete
+
+
+
+ ```
+
+
+
## Import
```tsx
@@ -28,7 +65,7 @@ import {
| Name | Type | Description |
|------|------|-------------|
| `AlertDialog` | Component | Root alert dialog context provider |
-| `AlertDialogTrigger` | Component | Button that opens the dialog; supports `asChild` |
+| `AlertDialogTrigger` | Component | Button that opens the dialog |
| `AlertDialogContent` | Component | Modal panel; includes overlay automatically |
| `AlertDialogHeader` | Component | Header section wrapper |
| `AlertDialogFooter` | Component | Footer section wrapper |
@@ -59,11 +96,10 @@ import {
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
- Button,
} from "@hareru/ui"
- Delete
+ Delete account
Are you sure?
diff --git a/apps/docs/content/docs/components/alert.mdx b/apps/docs/content/docs/components/alert.mdx
index c45c5af..e11cd07 100644
--- a/apps/docs/content/docs/components/alert.mdx
+++ b/apps/docs/content/docs/components/alert.mdx
@@ -5,6 +5,24 @@ description: Displays a feedback message to the user with optional title and des
**Category:** Feedback / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Alert, AlertTitle, AlertDescription } from "@hareru/ui"
+
+
+ Error
+ Something went wrong.
+
+ ```
+
+
+
Import from `@hareru/ui`:
```tsx
diff --git a/apps/docs/content/docs/components/approval-card.mdx b/apps/docs/content/docs/components/approval-card.mdx
index 1c22b09..33ad1b7 100644
--- a/apps/docs/content/docs/components/approval-card.mdx
+++ b/apps/docs/content/docs/components/approval-card.mdx
@@ -5,6 +5,28 @@ description: Human-in-the-loop approval card with approve/reject controls and ri
**Category:** AI / Chat / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ApprovalCard } from "@hareru/ui"
+
+ console.log("approved")}
+ onReject={() => console.log("rejected")}
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/aspect-ratio.mdx b/apps/docs/content/docs/components/aspect-ratio.mdx
index ecd2db3..28e0fbc 100644
--- a/apps/docs/content/docs/components/aspect-ratio.mdx
+++ b/apps/docs/content/docs/components/aspect-ratio.mdx
@@ -5,6 +5,27 @@ description: Container that enforces a fixed aspect ratio for its child content.
**Category:** Layout / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { AspectRatio } from "@hareru/ui"
+
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/async-combobox-field.mdx b/apps/docs/content/docs/components/async-combobox-field.mdx
index a445767..e93be37 100644
--- a/apps/docs/content/docs/components/async-combobox-field.mdx
+++ b/apps/docs/content/docs/components/async-combobox-field.mdx
@@ -5,6 +5,26 @@ description: Combobox with debounced async search, loading state, and integrated
**Category:** Form / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { AsyncComboboxField } from "@hareru/ui"
+
+ setSelectedAccount(value)}
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/avatar.mdx b/apps/docs/content/docs/components/avatar.mdx
index 9914f4f..19071e2 100644
--- a/apps/docs/content/docs/components/avatar.mdx
+++ b/apps/docs/content/docs/components/avatar.mdx
@@ -5,6 +5,24 @@ description: User avatar with automatic image load state management and initials
**Category:** Data Display / Global Service
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Avatar, AvatarImage, AvatarFallback } from "@hareru/ui"
+
+
+
+ YT
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/bento-grid.mdx b/apps/docs/content/docs/components/bento-grid.mdx
index 03b1895..8ed1455 100644
--- a/apps/docs/content/docs/components/bento-grid.mdx
+++ b/apps/docs/content/docs/components/bento-grid.mdx
@@ -7,6 +7,36 @@ description: Responsive drag-and-drop grid layout built on react-grid-layout wit
**Dependency:** `react-grid-layout`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { BentoGrid, BentoGridItem } from "@hareru/ui"
+ import { Card, CardContent, CardHeader, CardTitle } from "@hareru/ui"
+
+ const layouts = {
+ lg: [
+ { i: "a", x: 0, y: 0, w: 6, h: 2 },
+ { i: "b", x: 6, y: 0, w: 6, h: 2 },
+ ],
+ }
+
+
+
+ Visits 12,340
+
+
+ Revenue $4,200
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/breadcrumb.mdx b/apps/docs/content/docs/components/breadcrumb.mdx
index 2f2048d..5ac15b5 100644
--- a/apps/docs/content/docs/components/breadcrumb.mdx
+++ b/apps/docs/content/docs/components/breadcrumb.mdx
@@ -5,6 +5,42 @@ description: Navigation breadcrumb trail showing the current page location withi
**Category:** Navigation — **Pattern:** Pure React Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Breadcrumb,
+ BreadcrumbList,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+ } from "@hareru/ui"
+
+
+
+
+ Home
+
+
+
+ Products
+
+
+
+ Widget
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/chat-composer.mdx b/apps/docs/content/docs/components/chat-composer.mdx
index 5f865b7..1e4bf0e 100644
--- a/apps/docs/content/docs/components/chat-composer.mdx
+++ b/apps/docs/content/docs/components/chat-composer.mdx
@@ -5,6 +5,45 @@ description: Compound component for composing and submitting chat messages with
**Category:** AI / Chat / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { useState, type FormEvent } from "react"
+ import {
+ ChatComposer,
+ ChatComposerInput,
+ ChatComposerSend,
+ } from "@hareru/ui"
+
+ function MyChatInput() {
+ const [message, setMessage] = useState("")
+
+ const handleSubmit = (e: FormEvent) => {
+ if (!message.trim()) return
+ console.log("send:", message)
+ setMessage("")
+ }
+
+ return (
+
+
+
+
+ )
+ }
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/chat-container.mdx b/apps/docs/content/docs/components/chat-container.mdx
index e99ed4a..2564d60 100644
--- a/apps/docs/content/docs/components/chat-container.mdx
+++ b/apps/docs/content/docs/components/chat-container.mdx
@@ -5,6 +5,44 @@ description: Structural layout container with header, message list, and composer
**Category:** AI / Chat / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ ChatContainer,
+ ChatContainerHeader,
+ ChatContainerMessages,
+ ChatContainerFooter,
+ ChatMessage,
+ ChatComposer,
+ ChatComposerInput,
+ ChatComposerSend,
+ } from "@hareru/ui"
+
+
+
+ AI Assistant
+
+
+ Hello!
+ How can I help?
+
+
+
+
+
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/chat-message.mdx b/apps/docs/content/docs/components/chat-message.mdx
index e78edad..32e4a0a 100644
--- a/apps/docs/content/docs/components/chat-message.mdx
+++ b/apps/docs/content/docs/components/chat-message.mdx
@@ -5,6 +5,26 @@ description: Single chat bubble that renders user, assistant, or system messages
**Category:** AI / Chat / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ChatMessage, ChatMessageContent, ChatMessageTimestamp } from "@hareru/ui"
+
+ How do I create a new project?
+
+
+ Here's how to get started...
+ 10:30 AM
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/checkbox-group.mdx b/apps/docs/content/docs/components/checkbox-group.mdx
index 5e4ae63..deac332 100644
--- a/apps/docs/content/docs/components/checkbox-group.mdx
+++ b/apps/docs/content/docs/components/checkbox-group.mdx
@@ -7,6 +7,31 @@ description: Groups multiple Checkbox components with shared value state for mul
**Dependency:** `@base-ui-components/react/checkbox-group`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { CheckboxGroup, Checkbox } from "@hareru/ui"
+
+
+
+ Apple
+
+
+ Banana
+
+
+ Cherry
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/checkbox.mdx b/apps/docs/content/docs/components/checkbox.mdx
index 0ff64b8..e90ef37 100644
--- a/apps/docs/content/docs/components/checkbox.mdx
+++ b/apps/docs/content/docs/components/checkbox.mdx
@@ -7,6 +7,24 @@ description: Binary selection control with checked, unchecked, and indeterminate
**Dependency:** `@base-ui-components/react`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Checkbox, Label } from "@hareru/ui"
+
+
+
+ Accept terms and conditions
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/collapsible.mdx b/apps/docs/content/docs/components/collapsible.mdx
index fbb2ae5..0f98004 100644
--- a/apps/docs/content/docs/components/collapsible.mdx
+++ b/apps/docs/content/docs/components/collapsible.mdx
@@ -7,6 +7,28 @@ description: Accessible show/hide section that toggles between expanded and coll
**Dependency:** `@base-ui-components/react/collapsible`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Collapsible,
+ CollapsibleTrigger,
+ CollapsibleContent,
+ } from "@hareru/ui"
+
+
+ Show Details
+ Collapsible content
+
+ ```
+
+
+
## Import
```tsx
@@ -22,7 +44,7 @@ import {
| Name | Type | Description |
|------|------|-------------|
| `Collapsible` | Component | Root collapsible context; accepts `open`, `defaultOpen`, and `onOpenChange` |
-| `CollapsibleTrigger` | Component | Element that toggles the expanded state; supports `asChild` |
+| `CollapsibleTrigger` | Component | Element that toggles the expanded state |
| `CollapsibleContent` | Component | Section that is shown or hidden based on open state |
## Key Props
@@ -54,11 +76,10 @@ import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
- Button,
} from "@hareru/ui"
- Show Details
+ Show Details
Collapsible content
```
diff --git a/apps/docs/content/docs/components/combobox.mdx b/apps/docs/content/docs/components/combobox.mdx
index cb0a449..1a44848 100644
--- a/apps/docs/content/docs/components/combobox.mdx
+++ b/apps/docs/content/docs/components/combobox.mdx
@@ -7,6 +7,54 @@ description: Searchable select with popover overlay, built on Base UI Popover an
**Dependencies:** `@base-ui-components/react`, `cmdk`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { useState } from "react"
+ import {
+ Combobox,
+ ComboboxTrigger,
+ ComboboxContent,
+ ComboboxInput,
+ ComboboxList,
+ ComboboxItem,
+ ComboboxEmpty,
+ } from "@hareru/ui"
+
+ const fruits = [
+ { value: "apple", label: "Apple" },
+ { value: "banana", label: "Banana" },
+ { value: "cherry", label: "Cherry" },
+ ]
+
+ function FruitCombobox() {
+ const [value, setValue] = useState("")
+ return (
+
+ {value || "Select a fruit..."}
+
+
+
+ No results found
+ {fruits.map((fruit) => (
+ setValue(fruit.label)}>
+ {fruit.label}
+
+ ))}
+
+
+
+ )
+ }
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/command.mdx b/apps/docs/content/docs/components/command.mdx
index 11ba7c3..aff5306 100644
--- a/apps/docs/content/docs/components/command.mdx
+++ b/apps/docs/content/docs/components/command.mdx
@@ -7,6 +7,43 @@ description: Command palette with fuzzy search, built on cmdk.
**Dependency:** `cmdk`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { useState } from "react"
+ import {
+ CommandDialog,
+ CommandInput,
+ CommandList,
+ CommandEmpty,
+ CommandGroup,
+ CommandItem,
+ } from "@hareru/ui"
+
+ function CommandPalette() {
+ const [open, setOpen] = useState(false)
+ return (
+
+
+
+ No results
+
+ Settings
+ Profile
+
+
+
+ )
+ }
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/confidence-badge.mdx b/apps/docs/content/docs/components/confidence-badge.mdx
index c7fce7d..50929c2 100644
--- a/apps/docs/content/docs/components/confidence-badge.mdx
+++ b/apps/docs/content/docs/components/confidence-badge.mdx
@@ -5,6 +5,24 @@ description: Displays a confidence level with color-coded source-type styling an
**Category:** DI Domain / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ConfidenceBadge } from "@hareru/ui"
+
+
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/context-menu.mdx b/apps/docs/content/docs/components/context-menu.mdx
index d423a65..710fc07 100644
--- a/apps/docs/content/docs/components/context-menu.mdx
+++ b/apps/docs/content/docs/components/context-menu.mdx
@@ -7,6 +7,48 @@ description: Right-click context menu with items, checkboxes, radio items, separ
**Dependency:** `@base-ui-components/react/context-menu`, `@base-ui-components/react/menu`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ ContextMenu,
+ ContextMenuTrigger,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuLabel,
+ ContextMenuSeparator,
+ ContextMenuShortcut,
+ } from "@hareru/ui"
+
+
+
+
+ Right-click here
+
+
+
+ Edit
+
+
+ Cut Ctrl+X
+
+
+ Copy Ctrl+C
+
+
+ Paste Ctrl+V
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/data-quality-indicator.mdx b/apps/docs/content/docs/components/data-quality-indicator.mdx
index b8ae889..3402e87 100644
--- a/apps/docs/content/docs/components/data-quality-indicator.mdx
+++ b/apps/docs/content/docs/components/data-quality-indicator.mdx
@@ -5,6 +5,33 @@ description: Visual indicator of data quality score with dimension-level breakdo
**Category:** DI Domain / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { DataQualityIndicator } from "@hareru/ui"
+
+ console.log("show details")}
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/definition-browser.mdx b/apps/docs/content/docs/components/definition-browser.mdx
index caba4ee..01a3cbd 100644
--- a/apps/docs/content/docs/components/definition-browser.mdx
+++ b/apps/docs/content/docs/components/definition-browser.mdx
@@ -5,6 +5,39 @@ description: Tabbed browser for exploring semantic models, metrics, and dimensio
**Category:** DI Domain / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { DefinitionBrowser } from "@hareru/ui"
+
+ console.log("Selected:", metric)}
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/dropdown-menu.mdx b/apps/docs/content/docs/components/dropdown-menu.mdx
index aa71f01..052afd0 100644
--- a/apps/docs/content/docs/components/dropdown-menu.mdx
+++ b/apps/docs/content/docs/components/dropdown-menu.mdx
@@ -7,6 +7,39 @@ description: Accessible dropdown menu with support for groups, submenus, checkbo
**Dependency:** `@base-ui-components/react/menu`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ DropdownMenu,
+ DropdownMenuTrigger,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuLabel,
+ DropdownMenuSeparator,
+ Button,
+ } from "@hareru/ui"
+
+
+ Menu
+
+ Account
+
+ Profile
+ Settings
+
+ Log out
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/empty-state.mdx b/apps/docs/content/docs/components/empty-state.mdx
index 7832e25..142d736 100644
--- a/apps/docs/content/docs/components/empty-state.mdx
+++ b/apps/docs/content/docs/components/empty-state.mdx
@@ -5,6 +5,33 @@ description: Displays a placeholder UI when there is no content to show.
**Category:** Feedback / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ EmptyState,
+ EmptyStateTitle,
+ EmptyStateDescription,
+ EmptyStateAction,
+ Button,
+ } from "@hareru/ui"
+
+
+ No data found
+ Create your first item to get started.
+
+ Create New
+
+
+ ```
+
+
+
Import from `@hareru/ui`:
```tsx
diff --git a/apps/docs/content/docs/components/field-diff.mdx b/apps/docs/content/docs/components/field-diff.mdx
index e6eb6c3..7dcaf93 100644
--- a/apps/docs/content/docs/components/field-diff.mdx
+++ b/apps/docs/content/docs/components/field-diff.mdx
@@ -5,6 +5,26 @@ description: Side-by-side comparison of original and corrected field values with
**Category:** Data Display / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { FieldDiff } from "@hareru/ui"
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/form-field.mdx b/apps/docs/content/docs/components/form-field.mdx
index f666fb1..b1f3dda 100644
--- a/apps/docs/content/docs/components/form-field.mdx
+++ b/apps/docs/content/docs/components/form-field.mdx
@@ -5,6 +5,34 @@ description: Composite form field providing accessible label, control, descripti
**Category:** Form / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ FormField,
+ FormFieldLabel,
+ FormFieldControl,
+ FormFieldDescription,
+ FormFieldMessage,
+ Input,
+ } from "@hareru/ui"
+
+
+ Email
+
+
+
+ The email address used for login
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/key-value-list.mdx b/apps/docs/content/docs/components/key-value-list.mdx
index f8ca34a..11ba54e 100644
--- a/apps/docs/content/docs/components/key-value-list.mdx
+++ b/apps/docs/content/docs/components/key-value-list.mdx
@@ -5,6 +5,28 @@ description: Renders a list of key-value pairs in a definition-list style, suita
**Category:** Data Display / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { KeyValueList, Badge } from "@hareru/ui"
+
+ Active },
+ ]}
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/label.mdx b/apps/docs/content/docs/components/label.mdx
index 036ccff..5ecabac 100644
--- a/apps/docs/content/docs/components/label.mdx
+++ b/apps/docs/content/docs/components/label.mdx
@@ -5,6 +5,22 @@ description: Accessible form label built on a native HTML label element.
**Category:** Form / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Label, Input } from "@hareru/ui"
+
+ Email address
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/metric-card.mdx b/apps/docs/content/docs/components/metric-card.mdx
index b647fea..291d420 100644
--- a/apps/docs/content/docs/components/metric-card.mdx
+++ b/apps/docs/content/docs/components/metric-card.mdx
@@ -5,6 +5,27 @@ description: Dashboard tile that highlights a key metric value with freshness in
**Category:** DI Domain / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { MetricCard } from "@hareru/ui"
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/navigation-menu.mdx b/apps/docs/content/docs/components/navigation-menu.mdx
index f383957..d3906d4 100644
--- a/apps/docs/content/docs/components/navigation-menu.mdx
+++ b/apps/docs/content/docs/components/navigation-menu.mdx
@@ -7,6 +7,38 @@ description: Accessible top-level navigation menu with animated content panels,
**Dependency:** `@base-ui-components/react/navigation-menu`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ NavigationMenu,
+ NavigationMenuList,
+ NavigationMenuItem,
+ NavigationMenuTrigger,
+ NavigationMenuContent,
+ NavigationMenuLink,
+ } from "@hareru/ui"
+
+
+
+
+ Menu
+
+ About
+ Docs
+
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/pagination.mdx b/apps/docs/content/docs/components/pagination.mdx
index f1aa8ff..2831017 100644
--- a/apps/docs/content/docs/components/pagination.mdx
+++ b/apps/docs/content/docs/components/pagination.mdx
@@ -5,6 +5,46 @@ description: Page navigation with numbered links, previous/next controls, and el
**Category:** Navigation — **Pattern:** Pure React Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Pagination,
+ PaginationContent,
+ PaginationItem,
+ PaginationLink,
+ PaginationPrevious,
+ PaginationNext,
+ } from "@hareru/ui"
+
+
+
+
+ Previous
+
+
+ 1
+
+
+ 2
+
+
+ 3
+
+
+ Next
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/popover.mdx b/apps/docs/content/docs/components/popover.mdx
index 7ccef0c..980ec21 100644
--- a/apps/docs/content/docs/components/popover.mdx
+++ b/apps/docs/content/docs/components/popover.mdx
@@ -7,6 +7,29 @@ description: Non-modal floating panel anchored to a trigger element, built on Ba
**Dependency:** `@base-ui-components/react/popover`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Popover,
+ PopoverTrigger,
+ PopoverContent,
+ Button,
+ } from "@hareru/ui"
+
+
+ Open
+ Popover content
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/preview-card.mdx b/apps/docs/content/docs/components/preview-card.mdx
index 1589709..9af993c 100644
--- a/apps/docs/content/docs/components/preview-card.mdx
+++ b/apps/docs/content/docs/components/preview-card.mdx
@@ -7,6 +7,28 @@ description: Floating card that appears on hover over a link, showing a preview
**Dependency:** `@base-ui-components/react/preview-card`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { PreviewCard, PreviewCardTrigger, PreviewCardContent } from "@hareru/ui"
+
+
+
+ Example Website
+
+
+ A preview of the linked content appears here.
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/progress.mdx b/apps/docs/content/docs/components/progress.mdx
index dba96ee..39e631d 100644
--- a/apps/docs/content/docs/components/progress.mdx
+++ b/apps/docs/content/docs/components/progress.mdx
@@ -5,6 +5,21 @@ description: Displays a progress bar indicating how far along a task is.
**Category:** Feedback / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Progress } from "@hareru/ui"
+
+
+ ```
+
+
+
Import from `@hareru/ui`:
```tsx
diff --git a/apps/docs/content/docs/components/query-feedback.mdx b/apps/docs/content/docs/components/query-feedback.mdx
index 3af4d97..c3494fe 100644
--- a/apps/docs/content/docs/components/query-feedback.mdx
+++ b/apps/docs/content/docs/components/query-feedback.mdx
@@ -5,6 +5,23 @@ description: Collects binary helpful/unhelpful feedback on a query result or AI-
**Category:** DI Domain / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { QueryFeedback } from "@hareru/ui"
+
+ console.log("Feedback:", value)}
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/radio-group.mdx b/apps/docs/content/docs/components/radio-group.mdx
index d77c862..17b5eb2 100644
--- a/apps/docs/content/docs/components/radio-group.mdx
+++ b/apps/docs/content/docs/components/radio-group.mdx
@@ -7,6 +7,25 @@ description: Single-select group of radio button items, each with an indicator a
**Dependency:** `@base-ui-components/react`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { RadioGroup, RadioGroupItem } from "@hareru/ui"
+
+
+ Apple
+ Banana
+ Cherry
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/readonly-field.mdx b/apps/docs/content/docs/components/readonly-field.mdx
index fd098f1..25ead21 100644
--- a/apps/docs/content/docs/components/readonly-field.mdx
+++ b/apps/docs/content/docs/components/readonly-field.mdx
@@ -5,6 +5,22 @@ description: Displays a labeled field value in a read-only presentation, styled
**Category:** Data Display / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ReadonlyField, Badge } from "@hareru/ui"
+
+
+ Active} />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/reasoning-panel.mdx b/apps/docs/content/docs/components/reasoning-panel.mdx
index 473621f..f1916c8 100644
--- a/apps/docs/content/docs/components/reasoning-panel.mdx
+++ b/apps/docs/content/docs/components/reasoning-panel.mdx
@@ -5,6 +5,25 @@ description: Native details/summary disclosure widget that shows or hides an AI
**Category:** AI / Chat / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ReasoningPanel } from "@hareru/ui"
+
+
+ I considered three approaches: direct SQL query, semantic search,
+ and cached result lookup. The semantic search approach is most
+ appropriate because...
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/scroll-area.mdx b/apps/docs/content/docs/components/scroll-area.mdx
index a358064..d46eb61 100644
--- a/apps/docs/content/docs/components/scroll-area.mdx
+++ b/apps/docs/content/docs/components/scroll-area.mdx
@@ -7,6 +7,25 @@ description: Custom-styled scrollable container built on Base UI ScrollArea prim
**Dependency:** `@base-ui-components/react`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ScrollArea } from "@hareru/ui"
+
+
+
+ {longContent}
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/select.mdx b/apps/docs/content/docs/components/select.mdx
index 36e8f71..baa9f1a 100644
--- a/apps/docs/content/docs/components/select.mdx
+++ b/apps/docs/content/docs/components/select.mdx
@@ -7,6 +7,36 @@ description: Accessible dropdown select built on Base UI Select primitives.
**Dependency:** `@base-ui-components/react`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Select,
+ SelectValue,
+ SelectTrigger,
+ SelectContent,
+ SelectItem,
+ } from "@hareru/ui"
+
+
+
+
+
+
+ Apple
+ Banana
+ Cherry
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/semantic-suggest.mdx b/apps/docs/content/docs/components/semantic-suggest.mdx
index ae6c2af..032f30f 100644
--- a/apps/docs/content/docs/components/semantic-suggest.mdx
+++ b/apps/docs/content/docs/components/semantic-suggest.mdx
@@ -5,6 +5,29 @@ description: Suggestion card with type-based styling, evidence display, and acce
**Category:** DI Domain / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { SemanticSuggest } from "@hareru/ui"
+
+ console.log("accepted")}
+ onReject={() => console.log("dismissed")}
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/separator.mdx b/apps/docs/content/docs/components/separator.mdx
index 68b580c..e511b00 100644
--- a/apps/docs/content/docs/components/separator.mdx
+++ b/apps/docs/content/docs/components/separator.mdx
@@ -5,6 +5,27 @@ description: Visual divider line supporting horizontal and vertical orientations
**Category:** Layout / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Separator } from "@hareru/ui"
+
+
+
+
+ Left
+
+ Right
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/sheet.mdx b/apps/docs/content/docs/components/sheet.mdx
index 4f7a569..849ee31 100644
--- a/apps/docs/content/docs/components/sheet.mdx
+++ b/apps/docs/content/docs/components/sheet.mdx
@@ -7,6 +7,44 @@ description: Slide-in panel (drawer) anchored to any edge of the viewport, built
**Dependency:** `@base-ui-components/react/dialog`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Sheet,
+ SheetTrigger,
+ SheetClose,
+ SheetContent,
+ SheetHeader,
+ SheetFooter,
+ SheetTitle,
+ SheetDescription,
+ Button,
+ } from "@hareru/ui"
+
+
+ Open Panel
+
+
+ Settings
+ Modify your settings.
+
+ Content
+
+ Close
+ Save
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/skeleton.mdx b/apps/docs/content/docs/components/skeleton.mdx
index 3533cf6..40b4439 100644
--- a/apps/docs/content/docs/components/skeleton.mdx
+++ b/apps/docs/content/docs/components/skeleton.mdx
@@ -5,6 +5,27 @@ description: A loading placeholder that mimics the shape of content while it loa
**Category:** Feedback / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Skeleton } from "@hareru/ui"
+
+
+ ```
+
+
+
Import from `@hareru/ui`:
```tsx
diff --git a/apps/docs/content/docs/components/slider.mdx b/apps/docs/content/docs/components/slider.mdx
index 188e1cb..8026bfa 100644
--- a/apps/docs/content/docs/components/slider.mdx
+++ b/apps/docs/content/docs/components/slider.mdx
@@ -7,6 +7,33 @@ description: Input control for selecting a numeric value or range by dragging a
**Dependency:** `@base-ui-components/react/slider`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Slider,
+ SliderTrack,
+ SliderRange,
+ SliderThumb,
+ SliderOutput,
+ } from "@hareru/ui"
+
+
+
+
+
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/streaming-text.mdx b/apps/docs/content/docs/components/streaming-text.mdx
index 4d4ba20..19acbdf 100644
--- a/apps/docs/content/docs/components/streaming-text.mdx
+++ b/apps/docs/content/docs/components/streaming-text.mdx
@@ -5,6 +5,27 @@ description: Wraps streaming LLM output with an optional animated cursor indicat
**Category:** AI / Chat / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { StreamingText } from "@hareru/ui"
+
+
+ The answer to your question is...
+
+
+
+ The answer to your question is 42.
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/switch.mdx b/apps/docs/content/docs/components/switch.mdx
index ecce944..cf8531d 100644
--- a/apps/docs/content/docs/components/switch.mdx
+++ b/apps/docs/content/docs/components/switch.mdx
@@ -7,6 +7,24 @@ description: Accessible toggle switch built on Base UI Switch primitives.
**Dependency:** `@base-ui-components/react`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Switch, Label } from "@hareru/ui"
+
+
+
+ Enable notifications
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/table.mdx b/apps/docs/content/docs/components/table.mdx
index 1134a41..818a6c9 100644
--- a/apps/docs/content/docs/components/table.mdx
+++ b/apps/docs/content/docs/components/table.mdx
@@ -5,6 +5,49 @@ description: Semantic HTML table with styled header, body, and rows for displayi
**Category:** Data Display / Composite
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Table,
+ TableHeader,
+ TableBody,
+ TableRow,
+ TableHead,
+ TableCell,
+ Badge,
+ } from "@hareru/ui"
+
+
+
+
+ Name
+ Status
+ Amount
+
+
+
+
+ Invoice #001
+ Pending
+ $1,200.00
+
+
+ Invoice #002
+ Paid
+ $800.00
+
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/textarea.mdx b/apps/docs/content/docs/components/textarea.mdx
index 71566fe..4b22913 100644
--- a/apps/docs/content/docs/components/textarea.mdx
+++ b/apps/docs/content/docs/components/textarea.mdx
@@ -5,6 +5,21 @@ description: Multi-line text input with error state support.
**Category:** Form / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Textarea } from "@hareru/ui"
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/toast.mdx b/apps/docs/content/docs/components/toast.mdx
index 4175fbb..2fce90a 100644
--- a/apps/docs/content/docs/components/toast.mdx
+++ b/apps/docs/content/docs/components/toast.mdx
@@ -7,6 +7,23 @@ description: Displays brief, non-blocking notifications triggered imperatively v
**Dependency:** `@base-ui-components/react/toast`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { toast } from "@hareru/ui"
+
+ toast({ title: "Done", description: "The operation completed successfully." })
+
+ toast({ title: "Error", description: "Something went wrong.", variant: "destructive" })
+ ```
+
+
+
Import from `@hareru/ui`:
```tsx
diff --git a/apps/docs/content/docs/components/toggle-group.mdx b/apps/docs/content/docs/components/toggle-group.mdx
index df9f3c7..9b7ef09 100644
--- a/apps/docs/content/docs/components/toggle-group.mdx
+++ b/apps/docs/content/docs/components/toggle-group.mdx
@@ -7,6 +7,25 @@ description: Group of toggle buttons where one or multiple can be pressed, usefu
**Dependency:** `@base-ui-components/react/toggle-group`, `@base-ui-components/react/toggle`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ToggleGroup, ToggleGroupItem } from "@hareru/ui"
+
+
+ B
+ I
+ U
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/toggle.mdx b/apps/docs/content/docs/components/toggle.mdx
index 39ddbf8..5821f69 100644
--- a/apps/docs/content/docs/components/toggle.mdx
+++ b/apps/docs/content/docs/components/toggle.mdx
@@ -5,6 +5,25 @@ description: Pressable toggle button with pressed state tracking via aria-presse
**Category:** Form / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { Toggle } from "@hareru/ui"
+
+
+ B
+ I
+ U
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/tool-call-card.mdx b/apps/docs/content/docs/components/tool-call-card.mdx
index 4dbf78f..018061e 100644
--- a/apps/docs/content/docs/components/tool-call-card.mdx
+++ b/apps/docs/content/docs/components/tool-call-card.mdx
@@ -5,6 +5,28 @@ description: Displays a single agent tool invocation with its name, arguments, a
**Category:** AI / Chat / Standalone
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import { ToolCallCard } from "@hareru/ui"
+
+ Found 3 documents}
+ duration={245}
+ defaultExpanded
+ />
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/toolbar.mdx b/apps/docs/content/docs/components/toolbar.mdx
index 19be22c..4759f2a 100644
--- a/apps/docs/content/docs/components/toolbar.mdx
+++ b/apps/docs/content/docs/components/toolbar.mdx
@@ -7,6 +7,38 @@ description: Container for grouping action buttons, links, and separators into a
**Dependency:** `@base-ui-components/react/toolbar`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Toolbar,
+ ToolbarButton,
+ ToolbarGroup,
+ ToolbarSeparator,
+ } from "@hareru/ui"
+
+
+
+ B
+ I
+ U
+
+
+
+ Left
+ Center
+ Right
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/content/docs/components/tooltip.mdx b/apps/docs/content/docs/components/tooltip.mdx
index 819828b..ba253a8 100644
--- a/apps/docs/content/docs/components/tooltip.mdx
+++ b/apps/docs/content/docs/components/tooltip.mdx
@@ -7,6 +7,32 @@ description: Contextual label shown on hover or focus, built on Base UI Tooltip.
**Dependency:** `@base-ui-components/react/tooltip`
+## Preview
+
+
+
+
+
+
+ ```tsx
+ import {
+ Tooltip,
+ TooltipProvider,
+ TooltipTrigger,
+ TooltipContent,
+ Button,
+ } from "@hareru/ui"
+
+
+
+ Hover me
+ Tooltip content
+
+
+ ```
+
+
+
## Import
```tsx
diff --git a/apps/docs/scripts/verify-registry-docs.mjs b/apps/docs/scripts/verify-registry-docs.mjs
index c24af8f..55a4ad2 100644
--- a/apps/docs/scripts/verify-registry-docs.mjs
+++ b/apps/docs/scripts/verify-registry-docs.mjs
@@ -192,6 +192,43 @@ for (const entry of registry.components) {
}
}
+// ---------------------------------------------------------------------------
+// Preview coverage checks
+// ---------------------------------------------------------------------------
+
+// Load demo registry keys from demo-registry.ts
+const demoRegistryPath = join(docsRoot, 'app', 'components', 'preview', 'demo-registry.ts');
+const demoRegistrySource = readFileSync(demoRegistryPath, 'utf-8');
+const demoKeys = new Set([...demoRegistrySource.matchAll(/'([^']+)':\s*lazy/g)].map((m) => m[1]));
+
+for (const entry of registry.components) {
+ const mdx = mdxByTitle.get(entry.name);
+ if (!mdx) continue;
+
+ const { file, content } = mdx;
+
+ // Every component MDX must have ## Preview heading
+ const hasPreviewHeading = /^## Preview$/m.test(content);
+ if (!hasPreviewHeading) {
+ errors.push(`${file}: missing "## Preview" heading for "${entry.name}"`);
+ }
+
+ // Every component MDX must have not found in demo-registry.ts`);
+ }
+ }
+}
+
// ---------------------------------------------------------------------------
// Report
// ---------------------------------------------------------------------------