skui
A skeuomorphic CSS component library. All depth — bevels, gradients, shadows, noise texture — is driven by CSS custom properties. Swap one <link> to switch theme.
colors
#colorsAll themes expose identical variable names. Use only variables — never hardcode hex. Your components then adapt automatically when the theme changes.
/* backgrounds — darkest to brightest */
--bg-void /* deepest layer, page bg */
--bg-deep /* sunken wells, code blocks */
--bg-base /* main content canvas */
--bg-raised /* elevated panels */
--bg-float /* floating elements, popovers */
--bg-hover /* hover state fills */
/* accents */
--blue-t / --blue-b / --blue-lit / --blue-dim
--secondary-t / --secondary-b / --secondary-lit / --secondary-glow
/* semantic */
--danger-t / --danger-b
--success-t / --success-b
--warn-t / --warn-b
/* raised */
background: linear-gradient(180deg, var(--surf-t) 0%, var(--surf-b) 100%);
border: 1px solid var(--border-lo);
box-shadow: var(--bevel-hi), var(--bevel-lo), var(--shadow-md);
/* sunken */
background: var(--bg-deep);
border: 1px solid var(--border-lo);
box-shadow: var(--shadow-inset);
typography
#typographyStandard HTML elements are styled automatically. No classes needed for headings, body text, code, kbd, mark, or blockquote.
Display H1
Section H2
Subsection H3
Card title H4
Label H5
Micro label H6
Body text. Skeuomorphic design grants digital interfaces a sense of physical weight. Links feel deliberate. Bold emphasis. Italic for nuance. Inline code and keyboard ⌘K feel tangible. You can highlight passages.
Great interfaces are like a well-worn tool — the grain of the handle, the click of the switch, the weight in the hand.
box-shadow:
inset 0 1px 0 rgba(255,255,255,0.08),
inset 0 -1px 0 rgba(0,0,0,0.35),
0 3px 10px rgba(0,0,0,0.5);
<h1>Heading 1</h1>
<p>Body with <a>links</a>, <strong>bold</strong>, <em>italic</em>,
<code>code</code>, <kbd>Ctrl+K</kbd>, <mark>highlight</mark>.</p>
<blockquote>Quote</blockquote>
<pre><code>code block</code></pre>
panels
#panelsThe fundamental surface. Applies the raised gradient, bevel lines, border, and shadow as a unit. Use to group related content.
Standard raised surface. The gradient lifts the top edge; bevel lines create the 3D rim.
More prominent lift — use for floating elements, dropdowns, popovers.
panel--inset — sunken into the surface. Good for code output, read-only data, wells.
<div class="panel">content</div>
<div class="panel panel--raised">content</div>
<div class="panel panel--inset">content</div>
<!-- with header and footer -->
<div class="panel">
<div class="panel__header">Title</div>
content
<div class="panel__footer">
<button class="btn btn--ghost">Cancel</button>
<button class="btn btn--primary">Save</button>
</div>
</div>
buttons
#buttonsAll buttons share the base btn class. Combine with a variant and optionally a size modifier.
<button class="btn btn--primary">Primary</button>
<button class="btn btn--secondary">Secondary</button>
<button class="btn btn--ghost">Ghost</button>
<button class="btn btn--danger">Danger</button>
<button class="btn btn--success">Success</button>
<button class="btn btn--primary" disabled>Disabled</button>
<button class="btn btn--primary btn--sm">Small</button>
<button class="btn btn--primary btn--lg">Large</button>
<button class="btn btn--secondary btn--pill">Pill</button>
<button class="btn btn--ghost btn--icon">...svg...</button>
form elements
#formsInputs are sunken panels — they sit recessed using --shadow-inset. Labels, hints, and error states are separate elements alongside the input.
<div class="form-group">
<label class="form-label form-label--required">Name</label>
<input class="input" type="text" placeholder="...">
<span class="form-hint">hint text</span>
</div>
<!-- error state -->
<input class="input input--error">
<span class="form-error">message</span>
<textarea class="input" rows="4"></textarea>
<select class="select">
<option>Option A</option>
</select>
<label class="checkbox-wrap">
<input type="checkbox" checked>
<span class="checkbox-box"></span>
<span>Label text</span>
</label>
<label class="radio-wrap">
<input type="radio" name="group" checked>
<span class="radio-dot"></span>
<span>Option A</span>
</label>
<label class="toggle-wrap">
<input type="checkbox" checked>
<div class="toggle-track"><div class="toggle-thumb"></div></div>
<span>Label</span>
</label>
<input class="range" type="range" min="0" max="100" value="70">
badges & tags
#badgesBadges draw attention with accent colors. Tags are lower-contrast labels for classification and filtering.
<span class="badge badge--primary">Stable</span>
<span class="badge badge--secondary">Pro</span>
<span class="badge badge--success">Live</span>
<span class="badge badge--danger">Breaking</span>
<span class="badge badge--warn">Beta</span>
<span class="badge badge--muted">Archived</span>
<span class="tag">default</span>
<span class="tag tag--blue">feature</span>
<span class="tag tag--secondary">enhancement</span>
<span class="tag tag--red">critical</span>
<span class="tag tag--green">merged</span>
alerts
#alertsFull-width callout strips for feedback. Each variant maps to a semantic color role.
app.example.io.<div class="alert alert--info">...</div>
<div class="alert alert--success">...</div>
<div class="alert alert--warn">...</div>
<div class="alert alert--danger">...</div>
tabs
#tabsUses Alpine.js x-data for active state. The active tab receives tab--active. No other JS required.
<div x-data="{ tab: 'a' }">
<div class="tabs">
<button class="tab"
:class="tab === 'a' && 'tab--active'"
@click="tab='a'">Tab A</button>
</div>
<div x-show="tab === 'a'">Content A</div>
</div>
list items
#listUsed inside sidebars and navigation panels. list-section provides a muted group label; list-item--active highlights the selected row.
<div class="list-section">Group Label</div>
<div class="list-item list-item--active">Active item</div>
<div class="list-item">Normal item</div>
progress
#progressA sunken trough with a filled bar. Set fill width inline. Use progress__fill--secondary or --success for alternate accent colors.
<div class="progress">
<div class="progress__fill" style="width: 72%"></div>
</div>
<!-- color variants -->
progress__fill--secondary
progress__fill--success
avatars
#avatarsCircular (or square) initials/image containers. Wrap with avatar-wrap to attach a status dot.
<!-- sizes: avatar--sm avatar avatar--lg avatar--xl -->
<!-- shapes: default (circle), avatar--square -->
<!-- status: --online --idle --dnd --offline -->
<div class="avatar-wrap">
<div class="avatar" style="background:...">AB</div>
<span class="avatar-status avatar-status--online"></span>
</div>
tooltip
#tooltipPure CSS tooltip — no JavaScript. The tooltip appears above the trigger element on hover.
<span class="tooltip-wrap">
Hover me
<span class="tooltip">Tooltip content</span>
</span>
modal
#modalUses Alpine.js for open/close. The overlay receives is-open class to display. Clicking the backdrop closes it.
<button class="btn btn--primary" @click="modalOpen = true">Open</button>
<div class="overlay"
:class="modalOpen && 'is-open'"
@click.self="modalOpen = false">
<div class="modal">
<div class="modal__header">
<div class="modal__title">Title</div>
<button class="btn btn--ghost btn--icon btn--sm"
@click="modalOpen = false">✕</button>
</div>
<div class="modal__body">content</div>
<div class="modal__footer">
<button class="btn btn--ghost">Cancel</button>
<button class="btn btn--primary">Confirm</button>
</div>
</div>
</div>
table
#tableWrap <table> in .table-wrap for horizontal scroll and consistent border/shadow. Standard thead/tbody structure is all that's needed.
| Project | Status | Language | Updated | Actions |
|---|---|---|---|---|
HX helix-renderer |
Live | Rust | 2 hours ago | |
AU aurora-ui |
Beta | TypeScript | Yesterday | |
PX prism-core |
Archived | Go | 3 months ago |
<div class="table-wrap">
<table>
<thead><tr>
<th>Name</th>
<th>Status</th>
</tr></thead>
<tbody><tr>
<td>helix-renderer</td>
<td><span class="badge badge--success">Live</span></td>
</tr></tbody>
</table>
</div>