Olive is a Svelte component library and design system. It provides the visual language, design tokens, and component primitives for building professional, human-scale software tools.
Olive has a specific character — a way of feeling when you use it. It is not neutral. It is not generic. Every decision in this system is in service of that character.
Calm precision. The interface should feel like a well-organized workbench: everything in its place, nothing extraneous, the right tool within reach. There is no decoration for decoration's sake. Whitespace is not empty — it is the breathing room that lets content speak clearly. When the screen is calm, the user can focus on the work, not the interface.
Warmth without whimsy. Professional tools can have a soul. The color is a soft yellow-green — the color of a garden, of something grown. It does not scream. It does not demand attention. But it is unmistakably alive, and it makes the interface feel like something made by people who care. Empty states are friendly. Confirmations are human. Nothing is cold or corporate.
Trust through honesty. Olive is used to build tools that handle important things. The UI must communicate reliability. That means no layout shifts. No misleading affordances. No animation that obscures rather than clarifies. Numbers are formatted precisely. Errors say exactly what happened. Timestamps are readable. The system respects the user's intelligence and treats them as a professional.
Invisible infrastructure. The best UI moment is when the user stops thinking about the interface and thinks only about their work. Chrome — navbars, cards, borders, toolbars — is scaffolding. It should be there when needed and recede when not. Content is the primary element. Structure serves it.
Motion in Olive is purposeful. Every transition answers the question: "what changed, and where did it go?"
Animations communicate state, not personality. They orient the user — a panel slides in from the side so you know where it came from. A dialog fades up from center so you know it's floating above the page. A row highlights for 150ms so you know it was just updated.
Motion is never decorative. Nothing spins for the sake of spinning. Nothing bounces. Nothing draws attention to itself.
| Duration | Usage |
|---|---|
100ms |
Micro-feedback: button press, checkbox tick |
150ms |
Hover states, focus rings, badge color changes |
200ms |
Component appear/disappear (toast, tooltip, dropdown) |
250ms |
Panel slides, sheet entrances, modal fade-up |
350ms |
Page-level transitions, large layout changes |
Easing:
cubic-bezier(0.16, 1, 0.3, 1) — fast start, smooth landingcubic-bezier(0.4, 0, 1, 1) — quick, clean exitcubic-bezier(0.25, 0.46, 0.45, 0.94) — natural arcOnly ever animate opacity and transform. Never animate height, width, top, left, or any property that triggers layout. Layout animation causes jank. opacity + transform are GPU-composited and always smooth.
Do not show a loading indicator for operations under 200ms. Add a deliberate short delay before revealing any loading state — a spinner that flashes for 80ms is worse than no spinner at all.
Respect prefers-reduced-motion. Wrap all non-essential transitions in a media query check and disable or reduce them.
Text is the primary material of Olive interfaces. It should be legible at every size, on every screen, in both light and dark modes.
Primary font: Plus Jakarta Sans, weights 400/500/600/700. Its geometry is soft, slightly rounded — professional without being cold. It pairs naturally with the olive-green palette because both have warmth without loudness. Never substitute it. Never add additional font families.
Monospace font: ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace. Used for any content the user would copy-paste: identifiers, connection strings, keys, queries, payloads, schema names. If it came from a system or will go back into one, it is monospaced. This distinction is important — it immediately communicates "this is data" vs "this is UI".
Font smoothing is always on: -webkit-font-smoothing: antialiased. Sub-pixel rendering makes text look heavy on modern displays.
| Step | Size | Weight | Usage |
|---|---|---|---|
display |
2xl (1.5rem) |
semibold |
Page titles. One per page. |
title |
lg (1.125rem) |
semibold |
Card titles, section headers |
label |
sm (0.875rem) |
medium |
Nav items, form labels, column headers |
body |
sm (0.875rem) |
normal |
All body text |
caption |
xs (0.75rem) |
normal |
Metadata, timestamps, secondary info |
micro |
xs (0.75rem) + uppercase + tracking-wide |
medium |
Section labels, tiny category tags |
code |
sm (0.875rem) |
normal |
Inline code, monospaced content |
muted-foreground. It should be clearly subordinate, readable, but not competing.font-medium, font-semibold) instead. Reserve colored text for interactive elements and status indicators.max-w-prose (65ch) for reading text. Never let a line of prose stretch edge-to-edge.The palette is built around a yellow-green primary at hue ~75 — the color of fresh basil, of olives on the branch. It is warm, slightly muted, alive. Every neutral in the system carries a faint echo of this hue (hue 60–70) so the palette feels cohesive and nothing reads as cold or disconnected.
Backgrounds are never pure white or pure black. In light mode the background is a warm off-white. In dark mode it is a deep charcoal with a hint of green. This softness is deliberate — it reduces eye fatigue over long sessions and keeps the primary color from feeling harsh against it.
| Token | Light | Dark | Usage |
|---|---|---|---|
--background |
hsl(60 8% 95%) |
hsl(70 4% 9%) |
Page background |
--foreground |
hsl(70 8% 15%) |
hsl(60 8% 85%) |
Primary text |
--card |
hsl(60 6% 97%) |
hsl(70 4% 11%) |
Card and panel surfaces |
--card-foreground |
hsl(70 8% 15%) |
hsl(60 8% 85%) |
Text on card surfaces |
--muted |
hsl(65 8% 91%) |
hsl(70 4% 15%) |
Subtle fills, toggles, pill containers |
--muted-foreground |
hsl(70 4% 45%) |
hsl(65 4% 50%) |
Secondary text, metadata, placeholders |
--border |
hsl(65 6% 86%) |
hsl(70 4% 18%) |
Borders, dividers |
--primary |
hsl(75 60% 44%) |
hsl(75 55% 52%) |
Brand accent — buttons, focus rings, active states |
--primary-foreground |
hsl(70 8% 15%) |
hsl(70 4% 9%) |
Text on primary-colored surfaces |
--destructive |
hsl(0 55% 52%) |
hsl(0 45% 42%) |
Error, delete actions |
--destructive-foreground |
hsl(0 0% 98%) |
hsl(0 0% 98%) |
Text on destructive surfaces |
--ring |
hsl(75 60% 44%) |
hsl(75 55% 52%) |
Focus rings (equals --primary) |
--radius |
0.75rem |
— | Global border radius (12px) — cards, panels, inputs |
--radius-button |
0.4375rem |
— | Button border radius (7px) — tighter than cards for a more grounded feel |
Not used directly in components. These inform the semantic tokens.
olive-50 hsl(75 60% 96%)
olive-100 hsl(75 60% 90%)
olive-200 hsl(75 58% 78%)
olive-300 hsl(75 56% 66%)
olive-400 hsl(75 58% 54%)
olive-500 hsl(75 60% 44%) ← primary (light mode)
olive-600 hsl(75 55% 38%)
olive-700 hsl(75 50% 32%)
olive-800 hsl(75 45% 24%)
olive-900 hsl(75 40% 16%)
Status colors communicate state meaning. They are always used in icon backgrounds and small tints — never as large solid fills, which read as heavy.
| Status | Background | Text | Dark text | Usage |
|---|---|---|---|---|
| Success / Active | emerald-500/10 |
emerald-600 |
emerald-400 |
Active, running, OK |
| Warning / Paused | amber-500/10 |
amber-600 |
amber-400 |
Paused, pending, attention |
| Error | red-500/10 |
red-600 |
red-400 |
Errors, failures, deletes |
| Info | sky-500/10 |
sky-600 |
sky-400 |
Informational |
| Debug | purple-500/10 |
purple-600 |
purple-400 |
Debug, verbose |
| Trace | muted/50 |
muted-foreground |
muted-foreground |
Trace, lowest priority |
In dark mode: increase alpha to /15, shift text to the *-400 step.
For standalone status pills and type labels, use named CSS classes rather than composed Tailwind utilities. This is required for Tailwind v4 compatibility — composed utilities may not be generated if they don't appear in source.
| Class | Meaning |
|---|---|
.badge-active |
Active / running |
.badge-paused |
Paused / pending |
.badge-error |
Error / failed |
.badge-warning |
Warning / degraded |
.badge-info |
Informational |
.badge-debug |
Debug level |
.badge-trace |
Trace level |
.badge-write |
Write operation |
.badge-delete |
Delete operation |
text-primary, bg-muted, bg-primary/10) over hardcoded Tailwind colors for all brand and neutral elements.#000) or pure white (#fff). No cold gray Tailwind classes (gray-*, slate-*, zinc-*). Use the token system./10 tint. Never a solid fill.Olive interfaces must work on any screen — a phone held in one hand, a tablet at a café, a large monitor at a desk, and a display on a wall. This is not an afterthought. The layout system must flow gracefully across all of these.
| Name | Min-width | Typical device |
|---|---|---|
| (base) | 0px | Small phones |
sm |
640px | Large phones, small tablets |
md |
768px | Tablets |
lg |
1024px | Laptops |
xl |
1280px | Desktops |
2xl |
1536px | Wide monitors, TVs |
px-4 sm:px-6 lg:px-8 with max-w-7xl. Content breathes at every width.grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4. Never hardcode column counts for all screens.44×44px on touch screens. Use size="lg" for primary page-level CTAs on mobile. Never rely on hover for important affordances — touch devices have no hover state.overflow-x-auto) for tables and data views. Never clip or crop content — always provide a scroll path.2xl, content should not stretch uncomfortably wide. The max-w-7xl constraint applies everywhere. Very wide displays see more breathing room around the content, not wider content.sm and below.max-w-[calc(100vw-2rem)] on mobile — always inset from the screen edge.All spacing comes from the 4px/8px base scale. No arbitrary pixel values.
| Step | px | rem | Common use |
|---|---|---|---|
| 1 | 4px | 0.25rem | Tight internal gaps, icon margins |
| 2 | 8px | 0.5rem | Icon-to-label gaps, input padding |
| 3 | 12px | 0.75rem | Component internal padding |
| 4 | 16px | 1rem | Standard gap, card padding |
| 6 | 24px | 1.5rem | Section gaps, between form fields |
| 8 | 32px | 2rem | Between distinct content groups |
| 12 | 48px | 3rem | Between page sections |
| 16 | 64px | 4rem | Empty state padding, hero spacing |
Generous whitespace is not wasteful. It is what lets the eye move without effort. When in doubt, add more space, not less.
Shadows follow the foreground color at low opacity so they respect both light and dark themes.
--shadow-sm: 0 1px 2px hsl(var(--foreground) / 0.06);
--shadow-md: 0 4px 12px hsl(var(--foreground) / 0.08);
--shadow-lg: 0 8px 24px hsl(var(--foreground) / 0.10);
In dark mode: reduce alpha by ~30%. Never use box-shadow with hardcoded colors.
Two radius tokens. Use the right one for the right surface — they serve different visual roles.
| Token | Value | Use |
|---|---|---|
--radius |
0.75rem (12px) |
Cards, panels, inputs, dropdowns, dialogs — surfaces that contain content |
--radius-button |
0.4375rem (7px) |
Buttons only — tighter rounding grounds them visually and distinguishes them from containers |
Buttons use a smaller radius deliberately. Pill-shaped buttons (high radius) feel consumer and casual. A 7px radius reads as intentional and precise without feeling sharp.
Never use rounded-full on buttons. Avatars and purely decorative circular elements are the only exception.
Both modes are first-class. Every component must work in light mode, dark mode, and with system preference. This is not optional. Test both before considering a component done.
The CSS custom property system handles the majority of theming automatically. The soft, warm-tinted backgrounds mean dark mode looks like a candlelit room, not a cave. It is easy on the eyes for long sessions.
Implementation:
.dark class on the root element (<html> or <body>)localStorage as "light", "dark", or "system""system" — respect prefers-color-scheme unless overriddenWatch for these dark mode edge cases:
bg-card/80 — test that the blurred content behind reads well in both modes/10 to /15 in dark mode (dark:bg-emerald-500/15)dark: variants (text-emerald-600 dark:text-emerald-400)backdrop-blur): test that the overlay is legible over both light and dark content behind itAccessibility is not an enhancement — it is a baseline requirement.
--ring. Never suppress :focus-visible. Keyboard users navigate these interfaces too.44×44px for all interactive elements on touch screens.aria-label and a visible Tooltip.aria-live regions so screen readers catch them.prefers-reduced-motion. Wrap all transitions in the appropriate media query.The full Olive component inventory. All components are Svelte primitives exported from the library.
The atoms. Everything else composes from these.
| Component | Description |
|---|---|
Button |
Primary action surface. Variants: default, outline, ghost, destructive, link. Sizes: sm (28px), md (32px), lg (40px), icon (32px square). Uses --radius-button (7px). Default and destructive variants carry a subtle box-shadow for depth — inner top highlight and outer bottom shadow. Active state collapses the shadow inward. |
Input |
Text input. Focus ring, placeholder, disabled, error state. |
Textarea |
Multiline input. Vertical resize. |
Label |
Form field label, associated via for. |
Checkbox |
Binary toggle. Supports indeterminate state. |
RadioGroup + RadioItem |
Mutually exclusive option group. |
Select + SelectItem |
Dropdown selector. Keyboard navigable. |
Switch |
Toggle for boolean settings. |
Slider |
Range input. Single value and range variants. |
Badge |
Status and label pill. Variants map to semantic status colors. |
Avatar |
Image or initials identifier circle. |
Separator |
Horizontal or vertical divider. |
Structure and containment.
| Component | Description |
|---|---|
Card + CardHeader + CardTitle + CardDescription + CardContent + CardFooter |
Standard content container for any distinct entity. Do not nest cards unless there is a clear parent–child relationship. |
Page |
Outermost page wrapper. Applies background, max-width, standard padding. |
PageHeader |
Page title, description, and primary action slot. |
Breadcrumbs |
Hierarchical path navigation. |
Panel |
Fixed or floating side panel. Collapsible. |
Sidebar |
Persistent lateral navigation for section-level structure. |
Resizable |
Draggable split pane, horizontal or vertical. |
ScrollArea |
Custom scrollbar container. Cross-platform consistent. |
Tabs + TabList + Tab + TabPanel |
Section-level tab navigation. State-driven. |
| Component | Description |
|---|---|
Navbar |
Sticky top bar with backdrop blur. Logo, nav links, and actions slots. h-14 height. |
NavItem |
Single nav link. Icon + label or label only. Active state. |
MobileMenu |
Collapsible navigation panel for small screens. Opens from Navbar. |
ThemeToggle |
Light / dark / system mode toggle. Icon button with smooth icon transition. |
CommandPalette |
Keyboard-driven search and navigation overlay (⌘K). Debounced search, arrow-key navigation, shortcut hints. |
| Component | Description |
|---|---|
Dialog + DialogHeader + DialogContent + DialogFooter |
Modal for creation forms and destructive confirmations. Always requires explicit dismiss. |
Sheet |
Sliding panel from screen edge. For detail views and settings drawers. |
Tooltip |
Hover-activated label. Required on all icon-only buttons. |
Popover |
Anchored floating container for inline content. |
DropdownMenu + DropdownItem + DropdownSeparator |
Contextual action menu. Keyboard navigable. |
ContextMenu |
Right-click menu. Same structure as DropdownMenu. |
Toast |
Transient notification. Fixed bottom center. Auto-dismiss. Variants: default, success, warning, error. |
Alert |
Inline status message. Not dismissible. Variants: info, success, warning, error. |
AlertDialog |
Blocking confirmation for destructive actions. Explicit confirm + cancel required. |
Progress |
Linear progress bar. Determinate and indeterminate. Color maps to semantic status. |
Skeleton |
Loading placeholder. Matches the geometry of the content it replaces. |
| Component | Description |
|---|---|
Table + TableHeader + TableRow + TableCell + TableBody |
Tabular data. Sticky headers. Monospace cells for data values. Hover row. Truncation with tooltip. |
DataTable |
Table with sorting, filtering, and pagination built in. |
CodeBlock |
Syntax-highlighted code display. Monospace. Copy-to-clipboard. Language label. |
CodeEditor |
Monaco-based code editor. Dark/light theme sync. |
JsonViewer |
Collapsible JSON tree. Syntax highlighted. Copy individual values. |
KeyValue |
Compact key–value pair display. Monospace values. Copy action. |
MetricCard |
Single metric: icon with tinted background, label, value. |
StatGrid |
Responsive grid of MetricCards. |
EmptyState |
Centered message and CTA for zero-data views. Always includes a primary action. |
Timeline |
Interactive time-range control with play/pause/step playback. |
RelationsGraph |
SVG entity relationship diagram. Node cards, Bezier curve edges, hover labels. |
KanbanBoard + KanbanColumn + KanbanCard |
Drag-and-drop board. Columns with drop targets. Cards with hover-reveal actions. |
| Component | Description |
|---|---|
Form + FormField + FormLabel + FormControl + FormMessage |
Form structure with validation state, error messages, and accessible labeling. |
Combobox |
Searchable select with type-ahead. Keyboard navigable. |
MultiSelect |
Tag-style multi-value select. |
DatePicker |
Calendar popover for date selection. |
DateRangePicker |
Calendar popover for start and end date selection. |
FileUpload |
Drop zone and click-to-browse. Drag-over state. File type and size validation. |
SearchInput |
Input with search icon, clear button, and debounce. |
Purpose-built for technical and infrastructure contexts.
| Component | Description |
|---|---|
LogStream |
High-performance virtualized log viewer. Level badges, timestamp formatting, jump-to-bottom, pause-on-scroll. |
SqlEditor |
Monaco editor configured for SQL. Schema-aware autocomplete, execution state. |
SchemaView |
Table schema display: columns, types, constraints, indexes, foreign keys. |
ConnectionString |
Formatted connection string with copy action and optional value masking. |
ApiKeyCard |
Key display with masked value, type badge, copy button, created date, revoke action. |
OperationBadge |
Badge for data operation types (Write, Delete, Update) with semantic color. |
DrawCanvas |
Full-screen canvas. Tool states, pan, zoom, pointer event handling. |
Toolbar |
Fixed vertical or horizontal toolbar. Tool sections with icon buttons and collapse. |
PropertyPanel |
Collapsible properties sidebar. Sections, field rows with labels and controls. |
Layout & Spacing
max-w-7xl on all page content. Never edge-to-edge on wide screens.h-14. Present but not dominant.Typography
font-semibold for titles, font-medium for labels, font-normal for body.muted-foreground for secondary information.Color
/10–/15 alpha. No solid colored areas.Interactions
bg-card/80 backdrop-blur-xl) only for navbars and overlays.Data
1.2K, not 1200.Mar 11, 2026 or 2 hours ago. Never raw ISO strings.--primary is the only accent.!important.alert() or confirm().olive/
src/
lib/
components/
primitives/ # Button, Input, Badge, Label, Checkbox, etc.
layout/ # Card, Page, Panel, Sidebar, Tabs, etc.
navigation/ # Navbar, NavItem, ThemeToggle, CommandPalette, etc.
overlay/ # Dialog, Toast, Tooltip, Popover, Sheet, etc.
data/ # Table, DataTable, CodeBlock, MetricCard, etc.
forms/ # Form, Combobox, DatePicker, FileUpload, etc.
specialized/ # LogStream, SqlEditor, DrawCanvas, Toolbar, etc.
tokens/ # index.css — all CSS custom properties
utils/ # cn(), formatNumber(), formatDate(), formatBytes()
routes/
+page.svelte # Component showcase