Design System
v0.3A collection of components built with HTML and CSS variables, the same ones used in this portfolio. Copy the markup, customize the tokens, and ship faster.
Every token is a CSS custom property, one file to override the entire system.
Plain HTML + CSS. No bundler, no framework, no runtime required.
React components coming as @achmadalimin/ui, same
API, typed props.
Built-in dark default with a single
data-theme="light" switch.
Installation
Two ways to use it: copy the CSS directly into your project, or install via npm once the package is live.
Start in 30 seconds
Copy
design-system.css
into your project, add the CSS tokens, then copy the component
markup below.
$ curl -O https://achmadalimin.com/assets/css/design-system.css
npm (React — coming soon)
$ npm install @achmadalimin/ui
Theming
Override any token to match your brand. Set
data-theme="light"
on
<html>
to switch to light mode.
:root {
/* Backgrounds */
--ds-bg: #0f0f0f;
--ds-surface: #1a1a1a;
--ds-surface-hover: #222222;
--ds-code-bg: #161616;
/* Borders */
--ds-border: #2e2e2e;
--ds-border-subtle: #1f1f1f;
/* Text */
--ds-text: #f0f0f0;
--ds-text-muted: #777777;
--ds-text-faint: #3d3d3d;
/* Accent */
--ds-accent: #e8e8e8;
/* Semantic */
--ds-success: #4ade80;
--ds-warning: #fbbf24;
--ds-error: #f87171;
/* Shape & type */
--ds-radius: 0.5rem;
--ds-font: system-ui, sans-serif;
--ds-mono: ui-monospace, monospace;
}
[data-theme="light"] {
--ds-bg: #ffffff;
--ds-surface: #f0f0f0;
--ds-surface-hover: #e8e8e8;
--ds-code-bg: #f4f4f4;
--ds-border: #e2e2e2;
--ds-border-subtle: #ebebeb;
--ds-text: #1a1a1a;
--ds-text-muted: #6b6b6b;
--ds-text-faint: #9c9c9c;
--ds-accent: #111111;
}
Border
Two widths cover every use case. Color is set separately via
--color-border
tokens — keep them composable rather than pre-baked.
:root {
--border-width-1: 1px;
--border-width-2: 2px;
}
Radius
Four corner-radius steps cover everything from buttons to full pills.
:root {
--radius-sm: 0.5rem;
--radius-md: 0.75rem;
--radius-lg: 1rem;
--radius-full: 9999px;
}
Colors
Every color is a CSS custom property. Add your own
:root
overrides to rebrand the whole system. Swatches reflect the active
theme.
Base palette
Semantic
Icons
All icons used in this site. Each is a 16×16 SVG with
currentColor
fill so they inherit from their parent's color.
Logo
Brand assets for Achmad Alimin. Do not modify the letterforms or proportions, use the SVG files directly.
Wordmark
Logogram
Motion
Keyframe animations and easing curves used across the design system. All durations and curves are applied directly — no token abstraction needed.
Keyframes
Easing curves
Shadow
Four shadow levels built on
--ds-shadow-*
tokens. Each token adapts automatically to the active theme —
darker in dark mode, softer in light mode.
:root {
--ds-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.32);
--ds-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.32);
--ds-shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.40);
--ds-shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.48);
}
/* light theme overrides */
[data-theme="light"] {
--ds-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.08);
--ds-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.10);
--ds-shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.12);
--ds-shadow-xl: 0 20px 60px rgba(0, 0, 0, 0.15);
}
Space
4px-based scale for padding, margin, and gap. Numeric naming
(--space-1
through
--space-16) removes guesswork — multiply the number by 4 to get pixels.
:root {
--space-0: 0;
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
}
Typography
All components use a shared font stack. Override
--ds-font
or
--ds-mono
in your own
:root
to swap in a custom typeface.
Type scale
Font stacks
--ds-font:
-apple-system, BlinkMacSystemFont, "Inter",
"Segoe UI", ui-sans-serif, system-ui, sans-serif;
--ds-mono:
ui-monospace, "SF Mono", "Cascadia Code",
"Fira Code", Consolas, monospace;
Accordion
Collapsible content sections. Click a trigger to expand or collapse the panel below it.
@achmadalimin/ui.
<div class="ui-accordion">
<div class="ui-accordion-item">
<button class="ui-accordion-trigger" aria-expanded="false">
Accordion title
<svg class="ui-accordion-chevron" width="14" height="14"
viewBox="0 0 16 16" fill="none">
<path d="M4 6l4 4 4-4" stroke="currentColor"
stroke-width="1.5" stroke-linecap="round" />
</svg>
</button>
<div class="ui-accordion-content">
Accordion content goes here.
</div>
</div>
</div>
<script>
document.querySelectorAll(".ui-accordion-trigger").forEach(t => {
t.addEventListener("click", () => {
const open = t.getAttribute("aria-expanded") === "true";
t.setAttribute("aria-expanded", !open);
t.nextElementSibling.classList.toggle("open", !open);
});
});
</script>
import { Accordion, AccordionItem } from "@achmadalimin/ui"
<Accordion>
<AccordionItem title="Accordion title">
Accordion content goes here.
</AccordionItem>
</Accordion>
Badge
Small status and label indicator. Use it to highlight state, category, or metadata.
<span class="ui-badge ui-badge--default">Default</span>
<span class="ui-badge ui-badge--success">Success</span>
<span class="ui-badge ui-badge--warning">Warning</span>
<span class="ui-badge ui-badge--error">Error</span>
<span class="ui-badge ui-badge--outline">Outline</span>
import { Badge } from "@achmadalimin/ui"
<Badge>Default</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="warning">Warning</Badge>
<Badge variant="error">Error</Badge>
<Badge variant="outline">Outline</Badge>
Banner
Full-width notification strip for status messages, announcements, and inline alerts. Supports info, success, warning, and error variants, and an optional dismiss button.
Variants
<div class="ui-banner ui-banner--info">
<svg width="14" height="14" viewBox="0 0 16 16" fill="none">
<circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.3"/>
<path d="M8 5v4M8 11v.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
</svg>
<span class="ui-banner-body">Info message here.</span>
</div>
<!-- Variants: ui-banner--info | ui-banner--success | ui-banner--warning | ui-banner--error -->
import { Banner } from "@achmadalimin/ui"
<Banner variant="info">Info message here.</Banner>
<Banner variant="success">Your changes have been saved.</Banner>
<Banner variant="warning">This action may have side effects.</Banner>
<Banner variant="error">Something went wrong.</Banner>
Dismissible
<div class="ui-banner ui-banner--info">
<svg width="14" height="14" viewBox="0 0 16 16" fill="none">
<circle cx="8" cy="8" r="6.5" stroke="currentColor" stroke-width="1.3"/>
<path d="M8 5v4M8 11v.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>
</svg>
<span class="ui-banner-body">Dismissible banner.</span>
<button class="ui-banner-close" aria-label="Dismiss"
onclick="this.closest('.ui-banner').remove()">
<svg width="12" height="12" viewBox="0 0 12 12" fill="none">
<path d="M1 1l10 10M11 1L1 11" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</button>
</div>
import { Banner } from "@achmadalimin/ui"
<Banner variant="info" dismissible>
Dismissible banner.
</Banner>
Props
| Prop / Class | Type | Default | Description |
|---|---|---|---|
| ui-banner | class |
— | Base banner container |
| ui-banner--info | modifier |
— | Neutral informational style |
| ui-banner--success | modifier |
— | Green success state |
| ui-banner--warning | modifier |
— | Yellow warning state |
| ui-banner--error | modifier |
— | Red error state |
| ui-banner-body | class |
— | Text content wrapper inside the banner |
| ui-banner-close | class |
— | Optional dismiss button (×) |
| variant | "info" | "success" | "warning" | "error" |
"info" |
React prop for banner style variant |
| dismissible | boolean |
false |
React prop, shows a close button when true |
Button
Interactive button with four variants and three sizes. Use
<a>
or
<button>
same class works on both.
<button class="ui-btn ui-btn--primary">Primary</button>
<button class="ui-btn ui-btn--secondary">Secondary</button>
<button class="ui-btn ui-btn--outline">Outline</button>
<button class="ui-btn ui-btn--ghost">Ghost</button>
import { Button } from "@achmadalimin/ui"
<Button>Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
Sizes
<button class="ui-btn ui-btn--primary ui-btn--sm">Small</button>
<button class="ui-btn ui-btn--primary">Default</button>
<button class="ui-btn ui-btn--primary ui-btn--lg">Large</button>
<Button size="sm">Small</Button>
<Button>Default</Button>
<Button size="lg">Large</Button>
Disabled
<button class="ui-btn ui-btn--primary" disabled>Primary</button>
<Button disabled>Primary</Button>
Icon Only
<button class="ui-btn ui-btn--primary ui-btn--icon" aria-label="Share">
<img src="/assets/images/icons/share.svg" width="16" height="16" alt="">
</button>
<button class="ui-btn ui-btn--secondary ui-btn--icon" aria-label="Edit">
<img src="/assets/images/icons/edit.svg" width="16" height="16" alt="">
</button>
import { Button } from "@achmadalimin/ui"
<Button variant="primary" size="icon" aria-label="Share">
<ShareIcon />
</Button>
<Button variant="secondary" size="icon" aria-label="Edit">
<EditIcon />
</Button>
Props
| Prop / Class | Type | Default | Description |
|---|---|---|---|
| variant | primary | secondary | outline | ghost |
primary |
Visual style variant |
| size | sm | md | lg | icon |
md |
Button size; icon collapses to a square with no
padding
|
| disabled | boolean |
false |
Disabled and non-interactive |
Card
Versatile container with an optional header, body, and footer. Compose freely, all three regions are optional.
Card title
Supporting description text
<div class="ui-card">
<div class="ui-card-header">
<p class="ui-card-title">Card title</p>
<p class="ui-card-subtitle">Supporting description text</p>
</div>
<div class="ui-card-body">
Card body content goes here.
</div>
<div class="ui-card-footer">
<button class="ui-btn ui-btn--primary">Save changes</button>
<button class="ui-btn ui-btn--ghost">Cancel</button>
</div>
</div>
import { Card, Button } from "@achmadalimin/ui"
<Card
title="Card title"
subtitle="Supporting description text"
footer={
<>
<Button>Save changes</Button>
<Button variant="ghost">Cancel</Button>
</>
}
>
Card body content goes here.
</Card>
Input
Text input field with label, hint, and error state. Wrap in
.ui-field
for vertical stacking with a label.
<input class="ui-input" type="text" placeholder="Placeholder text" />
import { Input } from "@achmadalimin/ui"
<Input placeholder="Placeholder text" />
Props
| Class | Description |
|---|---|
| ui-field | Flex column wrapper for label + input + hint |
| ui-label | Field label |
| ui-input | Base input field |
| ui-input--error | Error border and focus ring |
| ui-hint | Helper text below the input |
| ui-hint--error | Error color for the hint |
Tabs
Horizontal tab navigation for switching between content panels. JavaScript handles the active state and panel visibility.
<div class="ui-tabs">
<div class="ui-tabs-list" role="tablist">
<div class="ui-tabs-slider"></div>
<button class="ui-tab-trigger active" aria-selected="true" role="tab">Overview</button>
<button class="ui-tab-trigger" aria-selected="false" role="tab">Details</button>
<button class="ui-tab-trigger" aria-selected="false" role="tab">Settings</button>
</div>
<div class="ui-tab-panel active">Overview content</div>
<div class="ui-tab-panel">Details content</div>
<div class="ui-tab-panel">Settings content</div>
</div>
<script>
document.querySelectorAll(".ui-tabs").forEach(tabs => {
const list = tabs.querySelector(".ui-tabs-list");
const slider = list.querySelector(".ui-tabs-slider");
const triggers = list.querySelectorAll(".ui-tab-trigger");
const panels = tabs.querySelectorAll(".ui-tab-panel");
function moveSlider(btn) {
const lr = list.getBoundingClientRect();
const br = btn.getBoundingClientRect();
slider.style.width = br.width + "px";
slider.style.transform = "translateX(" + (br.left - lr.left - 3) + "px)";
}
slider.style.transition = "none";
const initial = list.querySelector(".ui-tab-trigger.active");
if (initial) requestAnimationFrame(() => { moveSlider(initial); requestAnimationFrame(() => { slider.style.transition = ""; }); });
triggers.forEach((t, i) => t.addEventListener("click", () => {
triggers.forEach(x => { x.classList.remove("active"); x.setAttribute("aria-selected", "false"); });
panels.forEach(p => p.classList.remove("active"));
t.classList.add("active"); t.setAttribute("aria-selected", "true");
panels[i].classList.add("active");
moveSlider(t);
}));
});
</script>
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@achmadalimin/ui"
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="details">Details</TabsTrigger>
<TabsTrigger value="settings">Settings</TabsTrigger>
</TabsList>
<TabsContent value="overview">Overview content</TabsContent>
<TabsContent value="details">Details content</TabsContent>
<TabsContent value="settings">Settings content</TabsContent>
</Tabs>
Sizes
Default
Small:
ui-tabs--sm
<!-- Default -->
<div class="ui-tabs"> ... </div>
<!-- Small -->
<div class="ui-tabs ui-tabs--sm"> ... </div>
<!-- Default -->
<Tabs> ... </Tabs>
<!-- Small -->
<Tabs size="sm"> ... </Tabs>
Tooltip
Informational label that appears on hover or focus. CSS-only, no JavaScript required for basic usage.
<!-- Top (default) -->
<div class="ui-tooltip-wrap">
<button class="ui-btn ui-btn--secondary">Hover me</button>
<div class="ui-tooltip">Tooltip text</div>
</div>
<!-- Bottom -->
<div class="ui-tooltip-wrap">
<button class="ui-btn ui-btn--secondary">Hover me</button>
<div class="ui-tooltip ui-tooltip--bottom">Tooltip text</div>
</div>
import { Tooltip } from "@achmadalimin/ui"
<Tooltip content="Tooltip text">
<Button variant="secondary">Hover me</Button>
</Tooltip>
<Tooltip content="Bottom tooltip" side="bottom">
<Button variant="secondary">And me</Button>
</Tooltip>
Props
| Prop / Class | Type | Default | Description |
|---|---|---|---|
| ui-tooltip-wrap | class |
— | Wrapper that enables hover / focus detection |
| ui-tooltip | class |
— | The tooltip bubble, positioned above by default |
| ui-tooltip--bottom | modifier |
— | Positions the tooltip below the trigger |
| side | "top" | "bottom" |
"top" |
React prop for tooltip placement |
Modal
Overlay dialog for confirmations, alerts, and focused interactions. Closes on backdrop click or Escape key.
<!-- Trigger -->
<button class="ui-btn ui-btn--primary" onclick="document.getElementById('myModal').classList.add('open')">
Open modal
</button>
<!-- Modal -->
<div class="ui-modal-overlay" id="myModal">
<div class="ui-modal" role="dialog" aria-modal="true">
<p class="ui-modal-title">Modal title</p>
<p class="ui-modal-body">Modal content goes here.</p>
<div class="ui-modal-actions">
<button class="ui-modal-btn ui-modal-btn--cancel" onclick="document.getElementById('myModal').classList.remove('open')">Cancel</button>
<button class="ui-modal-btn ui-modal-btn--confirm">Confirm</button>
</div>
</div>
</div>
import { Modal } from "@achmadalimin/ui"
<Modal
open={isOpen}
onClose={() => setIsOpen(false)}
title="Modal title"
>
<p>Modal content goes here.</p>
<Modal.Actions>
<Modal.Cancel onClick={() => setIsOpen(false)}>Cancel</Modal.Cancel>
<Modal.Confirm>Confirm</Modal.Confirm>
</Modal.Actions>
</Modal>
Props
| Prop / Class | Type | Default | Description |
|---|---|---|---|
| ui-modal-overlay | class |
— | Full-screen backdrop — add .open to show |
| ui-modal-overlay.open | modifier |
— | Makes overlay visible and interactive |
| ui-modal | class |
— | The dialog panel |
| ui-modal-title | class |
— | Modal heading |
| ui-modal-body | class |
— | Main content area |
| ui-modal-actions | class |
— | Action row, right-aligned |
| ui-modal-btn | class |
— | Base button style for modal actions |
| ui-modal-btn--cancel | modifier |
— | Ghost/cancel style |
| ui-modal-btn--confirm | modifier |
— | Primary/confirm style |