Design System
A complete token-based design system derived from and powering krebsdesign.com. 22 native Web Components built on CSS custom properties, configurable, composable, and consistent.
Color Tokens
All colors are defined as CSS custom properties on :root. Edit them live using the Token Editor.
Typography
Inter carries the entire interface, body, UI, labels and headlines. A monospace stack (--font-code) is reserved for code only. Every family, size and weight shown here is read live from the design tokens, so this page always equals the site.
Spacing
An 8-step spacing scale from 4px to 64px. Used consistently for padding, margin, and gap throughout all components.
Border & Radius
Three border-radius tokens, from sharp corners to full pills. Border styles use semantic color tokens.
Shadow & Elevation
Three elevation levels. The default design uses flat aesthetics with border-based separation. Shadows are available as opt-in token overrides.
Motion
Purposeful, minimal motion. Fast for micro-interactions, base for transitions, slow for entrances.
| Token | Value | Use | Demo |
|---|---|---|---|
--dur-fast |
0.15s linear | Color changes, hover states, borders | |
--dur-base |
0.2s linear | Layout transitions, opacity, width | |
--dur-slow |
0.6s ease-out | Page entrances, slide-ins, reveals | |
--ease-out |
cubic-bezier(0.16,1,0.3,1) | Natural deceleration for enter animations | — |
Button
<dk-button>The primary action element. Four semantic variants cover every context from primary CTAs to destructive operations.
| Attribute | Type | Default | Description |
|---|---|---|---|
| variant | primary | secondary | ghost | danger |
primary |
Visual style of the button |
| size | sm | md | lg |
md |
Button size affecting padding and font |
| href | string |
— | When set, renders as an <a> element |
| loading | boolean |
— | Shows spinner, disables interaction |
| disabled | boolean |
— | Disables interaction |
<dk-button variant="primary">Get started</dk-button>
<dk-button variant="secondary">Learn more</dk-button>
<dk-button variant="ghost">Cancel</dk-button>
<dk-button variant="danger">Delete</dk-button>
<dk-button variant="primary" loading>Saving…</dk-button>
<dk-button variant="primary" href="/page">Navigate</dk-button>
Badge
<dk-badge>Small inline labels for status, categories, and counts. Six variants cover semantic states.
| Attribute | Type | Default | Description |
|---|---|---|---|
| variant | accent | muted | outline | success | warning | danger |
accent |
Color and style of the badge |
<dk-badge variant="accent">new</dk-badge>
<dk-badge variant="success">active</dk-badge>
<dk-badge variant="warning">pending</dk-badge>
<dk-badge variant="danger">error</dk-badge>
Pill
<dk-pill>Rounded metadata chips for locations, skills, and contextual information. Lighter than badges, no semantic color, just structure.
<dk-pill>munich · germany</dk-pill>
<dk-pill>design systems</dk-pill>
Tag
<dk-tag>Category tags for filtering and labelling. Supports a dismissible variant that emits a dk-dismiss event when removed.
| Attribute | Type | Default | Description |
|---|---|---|---|
| variant | default | bordered |
default |
bordered adds a border around the tag |
| dismissible | boolean |
— | Shows × button, emits dk-dismiss on click |
<dk-tag>brand</dk-tag>
<dk-tag variant="bordered">UX Research</dk-tag>
<dk-tag dismissible>removable</dk-tag>
Divider
<dk-divider>Horizontal separator with optional centered label. Adapts to the --color-rule token.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Optional text shown in the center of the line |
<dk-divider></dk-divider>
<dk-divider label="or"></dk-divider>
Section Header
<dk-section-header>Consistent page section headings with an optional category label and accent badge.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Small monospace category label |
| badge | string |
— | Accent-colored badge next to label |
| title | string |
— | Main heading text |
<dk-section-header label="work" badge="visual" title="Case Studies"></dk-section-header>
Card
<dk-card>Versatile container for grouped content. Supports attribute-based shortcuts for common patterns and named slots for custom layouts.
| Attribute | Type | Default | Description |
|---|---|---|---|
| tag | string |
— | Small category label above the title |
| title | string |
— | Card heading |
| desc | string |
— | Body text |
<dk-card tag="brand" title="Project Name" desc="Description text."></dk-card>
Input
<dk-input>Text input field with label, helper text, and validation state. Supports all standard HTML input types.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Input label text |
| type | text | email | password | number | search |
text |
HTML input type |
| placeholder | string |
— | Placeholder text |
| value | string |
— | Current value |
| helper | string |
— | Helper text below input |
| error | string |
— | Error message; also sets error visual state |
| required | boolean |
— | Shows required indicator |
| disabled | boolean |
— | Disables the field |
<dk-input label="Email" type="email" placeholder="you@example.com"></dk-input>
<dk-input label="Name" required error="This field is required."></dk-input>
Textarea
<dk-textarea>Multi-line text input for longer content like messages, descriptions, and notes.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Textarea label |
| placeholder | string |
— | Placeholder text |
| rows | number |
4 |
Visible rows height |
| helper | string |
— | Helper text below |
| error | string |
— | Error message |
| disabled | boolean |
— | Disables the field |
<dk-textarea label="Message" placeholder="Your message…" rows="5"></dk-textarea>
Select
<dk-select>Styled dropdown selector consistent with the Input component. Options passed as JSON attribute.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Select label |
| placeholder | string |
— | Placeholder option text |
| options | JSON string |
— | Array of {value, label} objects |
| value | string |
— | Currently selected value |
| error | string |
— | Error message |
| disabled | boolean |
— | Disables the field |
<dk-select label="Country" options='[{"value":"de","label":"Germany"}]'></dk-select>
Checkbox
<dk-checkbox>Custom-styled checkbox with label. Supports checked, indeterminate, and disabled states.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Label text beside the checkbox |
| checked | boolean |
— | Checked state |
| indeterminate | boolean |
— | Indeterminate state (partial selection) |
| disabled | boolean |
— | Disables interaction |
| name | string |
— | Form field name |
| value | string |
— | Form field value |
<dk-checkbox label="Accept terms" checked></dk-checkbox>
Radio Group
<dk-radio-group>Mutually exclusive selection from a set of options. Options are passed as a JSON attribute.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Group label |
| name | string |
— | Form field name shared by all radios |
| options | JSON string |
— | Array of {value, label} objects |
| value | string |
— | Currently selected value |
<dk-radio-group name="size" options='[{"value":"s","label":"Small"},{"value":"m","label":"Medium"}]'></dk-radio-group>
Toggle
<dk-toggle>On/off switch for boolean settings. Ideal for feature flags, preferences, and settings panels.
| Attribute | Type | Default | Description |
|---|---|---|---|
| label | string |
— | Label text |
| checked | boolean |
— | Current on/off state |
| disabled | boolean |
— | Disables interaction |
<dk-toggle label="Enable notifications"></dk-toggle>
<dk-toggle label="Dark mode" checked></dk-toggle>
Alert
<dk-alert>Inline feedback banners for communicating status to users. Supports a dismissible variant with an optional title.
| Attribute | Type | Default | Description |
|---|---|---|---|
| variant | info | success | warning | danger |
info |
Semantic color of the alert |
| title | string |
— | Bold heading above the content |
| dismissible | boolean |
— | Shows × button to hide the alert |
<dk-alert variant="success" title="Saved">Your changes were saved.</dk-alert>
<dk-alert variant="danger" dismissible>Something went wrong.</dk-alert>
Tooltip
<dk-tooltip>Contextual information shown on hover. Wraps any content, hover the examples below to see them in action.
| Attribute | Type | Default | Description |
|---|---|---|---|
| content | string |
— | Tooltip text content |
| placement | top | bottom | left | right |
top |
Preferred position relative to trigger |
<dk-tooltip content="Helpful context" placement="top">
<dk-button>hover me</dk-button>
</dk-tooltip>
Spinner
<dk-spinner>Animated loading indicator. Three sizes for different contexts.
| Attribute | Type | Default | Description |
|---|---|---|---|
| size | sm | md | lg |
md |
Spinner diameter (16 / 24 / 40px) |
<dk-spinner size="md"></dk-spinner>
Progress
<dk-progress>Linear progress bar for upload states, multi-step forms, and loading sequences.
| Attribute | Type | Default | Description |
|---|---|---|---|
| value | number (0–100) |
— | Current progress percentage |
| label | string |
— | Label shown above the bar |
<dk-progress value="60" label="Uploading…"></dk-progress>
Avatar
<dk-avatar>User representation as initials or image. Falls back gracefully to initials when no image source is provided.
| Attribute | Type | Default | Description |
|---|---|---|---|
| initials | string |
— | 1–2 character abbreviation |
| src | string |
— | Image URL; shows image instead of initials |
| size | sm | md | lg |
md |
Avatar diameter (28 / 40 / 56px) |
| alt | string |
— | Alt text for image variant |
<dk-avatar initials="DK" size="md"></dk-avatar>
<dk-avatar src="/avatar.jpg" alt="David Krebs" size="lg"></dk-avatar>
Tabs
<dk-tabs> / <dk-tab>Content organized into selectable panels. Uses slot composition, each dk-tab child becomes a panel.
<dk-tabs>
<dk-tab label="Overview">Content A</dk-tab>
<dk-tab label="Details">Content B</dk-tab>
<dk-tab label="History">Content C</dk-tab>
</dk-tabs>
Accordion
<dk-accordion> / <dk-accordion-item>Vertically stacked expandable sections. Useful for FAQs, settings panels, and content that benefits from progressive disclosure.
<dk-accordion>
<dk-accordion-item title="Question one?">Answer text here.</dk-accordion-item>
<dk-accordion-item title="Question two?">Another answer.</dk-accordion-item>
</dk-accordion>
Table
<dk-table>Structured data display with sortable columns, striped rows, and hover states. Columns and rows passed as JSON attributes.
| Attribute | Type | Default | Description |
|---|---|---|---|
| columns | JSON string |
— | Array of {key, label} column definitions |
| rows | JSON string |
— | Array of data objects matching column keys |
| striped | boolean |
— | Alternating row background |
| bordered | boolean |
— | Full cell borders |
<dk-table
columns='[{"key":"name","label":"Name"},{"key":"role","label":"Role"}]'
rows='[{"name":"David","role":"Designer"},{"name":"Alex","role":"Developer"}]'
striped>
</dk-table>
Breadcrumb
<dk-breadcrumb>Navigation path indicator. Last item is the current page. Items passed as JSON.
| Attribute | Type | Default | Description |
|---|---|---|---|
| items | JSON string |
— | Array of {label, href?}, last item has no link |
<dk-breadcrumb items='[{"label":"Home","href":"/"},{"label":"Current Page"}]'></dk-breadcrumb>
Chapter Intro (Case module)
block: chapterEditorial case module. A chapter opener with a mono eyebrow, a large headline (bold = accent, italic = thin) and an optional lead. Structures a case story into chapters with generous whitespace, no section numbering.
From skeuomorphic to token-based
Mono eyebrow, large editorial headline and an optional lead.
| Attribute | Type | Default | Description |
|---|---|---|---|
| eyebrow | text (DE/EN) |
— | Small mono label above the headline |
| headline | writer (DE/EN) |
— | bold = accent, italic = thin |
| lead | textarea (DE/EN) |
— | Optional intro paragraph |
| align | left / center |
left |
Text alignment |
| spacing | small / normal / large |
large |
Vertical whitespace |
Panel: Case, Inhalt, Struktur und Text, Kapitel-Intro
Text + Media (Case module)
block: text-mediaEditorial case module. A narrow text column beside one or more stacked images. With sticky on, the text stays fixed while the images scroll past; on mobile it collapses to a stack. Captions come from the media library.
Every function, a clear surface
Sticky text beside a stack of images.
| Attribute | Type | Default | Description |
|---|---|---|---|
| eyebrow / headline / body | DE/EN |
— | Text column content |
| images | files |
— | One or more stacked images |
| mediaSide | left / right |
right |
Which side the images sit on |
| split | 1/3, 2/5, 1/2 |
1/3 |
Text-to-media width ratio |
| sticky | on / off |
1 |
Text stays fixed while images scroll |
| objectFit | contain / cover |
contain |
Whole image vs cropped |
Panel: Case, Inhalt, Bilder und Medien, Text-neben-Bild
Image Duo/Trio (Case module)
block: image-rowEditorial case module. Two or three images side by side. Equal or unequal split (60/40), per-block fit and width (Normal, Wide, Full-bleed). Captions from the media library. Related: the Image block gained a width option and the Quote block an editorial variant.
| Attribute | Type | Default | Description |
|---|---|---|---|
| images | files (2 to 3) |
— | Images left to right |
| layout | equal / wideLeft / wideRight |
equal |
Unequal 60/40 for two images |
| blockWidth | normal / wide / full |
wide |
Reading column, breakout, or full-bleed |
| objectFit | cover / contain |
cover |
Equal-height crop vs whole image |
| gap | small / medium / large |
medium |
Space between images |
Panel: Case, Inhalt, Bilder und Medien, Bild-Duo/Trio