Sabil UI

Search documentation

Search for a command to run...

Getting Started

AI & LLMs

Paste this page (or its Markdown at /docs/ai.md) into any AI assistant before asking it to build UI. It tells the model exactly how Sabil UI looks and which pieces to use.

Quick start#

Give your assistant the link to the rules together with your request:

Build a settings page for a SaaS app with Sabil UI.Follow the rules at https://ui.muttaqinsabilul.my.id/docs/ai.md and use only its components and tokens.
Or copy all rules as Markdown and paste them into the chat.Copy rules

Machine-readable files#

/llms.txtIndex of every page, for assistants that read links.
/llms-full.txtAll docs in one file: rules, foundation, components, motion.
/docs/ai.mdThese rules as Markdown.
<any page>.mdEvery page has a Markdown twin, e.g. /docs/components/button.md.
/tokens.jsonDesign tokens in the W3C Design Tokens format.
/r/index.jsonComponent registry: source, dependencies and files of every component.
/docs/mcpMCP server (endpoint /mcp) for Claude Code, Cursor and VS Code.

Stack#

  • React with Tailwind CSS v4 and Radix UI primitives. Components live in @/components/ui/<name> and are imported by name, e.g. import { Button } from "@/components/ui/button".
  • Merge class names with cn from @/lib/utils.
  • Icons come from lucide-react. Inside buttons, icons are 16px and need no size class.
  • Motion: CSS for press, hover and overlays; the motion package (import { motion } from "motion/react") for springs, gestures, exit and layout animation.
  • Without React or Tailwind, use the plain edition: sabil.css + sabil.js with s-* classes (see /docs/html-css).

Use tokens, never raw values#

Always use the semantic Tailwind classes below. Never hard-code hex colors, pixel radii or shadows.

PurposeClassLightDark
Page backgroundbg-background#ffffff#0a0a0a
Texttext-foreground#0a0a0a#fafafa
Secondary texttext-muted-foreground#45556c#a1a1a6
Primary action (blue)bg-primary / text-primary#056dff#2b7bff
Subtle fill, tracksbg-muted / bg-secondary#f1f5f9#1d1d1f
Hover fillbg-accent#0a0a0a 4%#ffffff 6%
Hairlineborder / border-border#0a0a0a 8%#ffffff 9%
Dangerbg-destructive / text-destructive#e7000b#ff6467
Cards, popoversbg-card / bg-popover#ffffff#121212 / #161616
Warm preview panelbg-panel#f9f8f6#1a1918

Size and shape#

ElementValueClass
Buttons, inputs, selects (default)40px highbuilt into the components
Small controls32px highsize="sm"
Tab trigger6px radiusrounded-md
Controls, menu items8px radiusrounded-lg
Menus, popovers, dialogs, cards12px radiusrounded-xl
Large cards, chat bubbles16px radiusrounded-2xl
FontInter; Geist Mono for codefont-sans / font-mono
Body text14pxtext-sm
Button text14px, 500, -0.01em trackingbuilt in
Headingssemibold, tight trackingfont-semibold tracking-tight

Surfaces#

  • Primary actions use <Button> (default variant): a blue vertical gradient (#3c86ff → #056dff) with a 1px inner edge. Do not restyle it with bg-blue-*.
  • Secondary actions use <Button variant="outline">: white, hairline ring, 0 1px 2px shadow.
  • One primary button per view or form. Everything else is outline, secondary or ghost.
  • Segmented controls and tabs sit on a flat slate track (bg-muted, 2px padding); the active item is white with shadow-xs.
  • Menus and popovers: bg-popover, rounded-xl, a 6% hairline ring and a soft shadow-lg. Items are rounded-lg.
  • Utilities available: surface-primary, surface-raised, surface-sunken, bg-dots (dotted canvas).

Pick the right component#

Prefer an existing component over custom markup. All 66 are listed at /docs/components.

NeedUse
ActionButton, ButtonGroup
Form fieldField + Label + Input / Textarea / Select / Checkbox / Switch / RadioGroup
Pick one of a few optionsTabs (segmented) or ToggleGroup
Search a long listCombobox or Command
Confirm a destructive actionAlertDialog
Form or details on top of the pageDialog (desktop) or Drawer / Sheet (mobile, side panels)
Actions behind a buttonDropdownMenu
Site navigation with previewsNavigationMenu
Status or feedbackBadge, Alert, Toast (sonner), Progress, Spinner, Skeleton
Content blockCard, Item, Empty
DataTable, DataTable, Chart
Chat UIMessage, Bubble, MessageScroller, Attachment

Motion#

  • Easing: ease-out for enter, exit and feedback (it is overridden to cubic-bezier(0.23, 1, 0.32, 1)); ease-in-out for movement on screen. Never ease-in.
  • Durations: press 150ms, tooltips and menus 150–200ms, dialogs 200–300ms, drawers 400ms. Keep interface motion under 300ms.
  • Pressable elements scale to 0.97 on press. Buttons already do this.
  • Enter from scale(0.95) + opacity: 0, never from scale(0). Exit faster than enter.
  • Animate transform and opacity only. Never transition: all.
  • No animation on things opened from the keyboard many times a day (command palettes, shortcuts).
  • Respect prefers-reduced-motion: in Motion, read useReducedMotion() and drop movement.

Do not#

  • Do not use raw Tailwind palette colors (bg-blue-500, text-gray-600, border-zinc-200). Use the tokens.
  • Do not add borders to primary buttons or change button heights by hand.
  • Do not mix radii: controls rounded-lg, containers rounded-xl.
  • Do not use pure black text on white for secondary copy; use text-muted-foreground.
  • Do not use more than one primary (blue) button in a group.
  • Do not invent new shadows. Use shadow-xs for raised controls and shadow-lg for overlays.

Example#

A sign-in card that follows every rule above.

import { Button } from "@/components/ui/button"import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"import { Field, FieldLabel } from "@/components/ui/field"import { Input } from "@/components/ui/input"export function SignIn() {  return (    <Card className="w-full max-w-sm">      <CardHeader>        <CardTitle>Sign in</CardTitle>        <CardDescription>Use your work email.</CardDescription>      </CardHeader>      <CardContent className="grid gap-4">        <Field>          <FieldLabel htmlFor="email">Email</FieldLabel>          <Input id="email" type="email" placeholder="you@example.com" />        </Field>        <Field>          <FieldLabel htmlFor="password">Password</FieldLabel>          <Input id="password" type="password" />        </Field>      </CardContent>      <CardFooter className="flex-col gap-2">        <Button className="w-full">Sign in</Button>        <Button variant="outline" className="w-full">Continue with SSO</Button>      </CardFooter>    </Card>  )}