UI Library

A lightweight CSS component library with nested CSS and configurable colors.

Theme Configurator

Pick colors to live-update the entire page

Buttons

Solid variants

Show code
<button class="ui-btn">Primary</button>
<button class="ui-btn secondary">Secondary</button>
<button class="ui-btn success">Success</button>
<button class="ui-btn danger">Danger</button>
<button class="ui-btn warning">Warning</button>
<button class="ui-btn" disabled>Disabled</button>

Outline variants

Show code
<button class="ui-btn outline">Primary</button>
<button class="ui-btn outline secondary">Secondary</button>
<button class="ui-btn outline success">Success</button>
<button class="ui-btn outline danger">Danger</button>

Ghost variants

Show code
<button class="ui-btn ghost">Primary</button>
<button class="ui-btn ghost secondary">Secondary</button>
<button class="ui-btn ghost danger">Danger</button>

Sizes

Show code
<button class="ui-btn sm">Small</button>
<button class="ui-btn">Default</button>
<button class="ui-btn lg">Large</button>

Shapes & groups

Show code
<button class="ui-btn pill">Pill button</button>
<button class="ui-btn pill outline secondary">Pill outline</button>

<div class="ui-btn-group">
  <button class="ui-btn outline">Left</button>
  <button class="ui-btn outline">Center</button>
  <button class="ui-btn outline">Right</button>
</div>

With icons

Show code
<button class="ui-btn"><i class="bi bi-plus-lg"></i> Add item</button>
<button class="ui-btn outline secondary"><i class="bi bi-pencil"></i> Edit</button>
<button class="ui-btn danger"><i class="bi bi-trash"></i> Delete</button>
<button class="ui-btn ghost"><i class="bi bi-download"></i> Download</button>
<button class="ui-btn success"><i class="bi bi-check-lg"></i> Approve</button>
<button class="ui-btn outline icon" title="Settings"><i class="bi bi-gear"></i></button>
<button class="ui-btn icon" title="Search"><i class="bi bi-search"></i></button>

Loading state

Show code
<button class="ui-btn loading">Saving</button>
<button class="ui-btn secondary loading">Loading</button>
<button class="ui-btn outline loading">Submit</button>
<button class="ui-btn ghost loading">Fetch</button>
<button class="ui-btn danger loading">Delete</button>
<button class="ui-btn sm loading">Small</button>
<button class="ui-btn lg loading">Large</button>

<!-- Toggle loading via JS -->
<script>
const btn = document.querySelector('.ui-btn');
btn.classList.add('loading');    // start
btn.classList.remove('loading'); // stop
</script>

Toggle Buttons

Default

Show code
<label class="ui-toggle">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Enabled
</label>
<label class="ui-toggle">
  <input type="checkbox">
  <span class="ui-toggle-track"></span>
  Disabled
</label>

Color variants

Show code
<label class="ui-toggle">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Primary
</label>
<label class="ui-toggle success">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Success
</label>
<label class="ui-toggle danger">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Danger
</label>
<label class="ui-toggle warning">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Warning
</label>

Sizes

Show code
<label class="ui-toggle sm">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Small
</label>
<label class="ui-toggle">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Default
</label>
<label class="ui-toggle lg">
  <input type="checkbox" checked>
  <span class="ui-toggle-track"></span>
  Large
</label>

Disabled state

Show code
<label class="ui-toggle">
  <input type="checkbox" disabled>
  <span class="ui-toggle-track"></span>
  Off (disabled)
</label>
<label class="ui-toggle">
  <input type="checkbox" checked disabled>
  <span class="ui-toggle-track"></span>
  On (disabled)
</label>

Checkboxes & Radios

Checkboxes

Show code
<label class="ui-checkbox">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Checked
</label>
<label class="ui-checkbox">
  <input type="checkbox">
  <span class="ui-check-box"></span>
  Unchecked
</label>
<label class="ui-checkbox">
  <input type="checkbox" id="indeterminate-cb">
  <span class="ui-check-box"></span>
  Indeterminate
</label>
<label class="ui-checkbox">
  <input type="checkbox" checked disabled>
  <span class="ui-check-box"></span>
  Disabled (checked)
</label>
<label class="ui-checkbox">
  <input type="checkbox" disabled>
  <span class="ui-check-box"></span>
  Disabled (unchecked)
</label>

<script>
// Indeterminate is a JS-only property, cannot be set via HTML
document.getElementById('indeterminate-cb').indeterminate = true;
</script>

Checkbox colors

Show code
<label class="ui-checkbox">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Primary
</label>
<label class="ui-checkbox success">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Success
</label>
<label class="ui-checkbox danger">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Danger
</label>
<label class="ui-checkbox warning">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Warning
</label>

Checkbox sizes

Show code
<label class="ui-checkbox sm">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Small
</label>
<label class="ui-checkbox">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Default
</label>
<label class="ui-checkbox lg">
  <input type="checkbox" checked>
  <span class="ui-check-box"></span>
  Large
</label>

Radio buttons

Show code
<label class="ui-radio">
  <input type="radio" name="demo-radio-1" checked>
  <span class="ui-check-box"></span>
  Option one
</label>
<label class="ui-radio">
  <input type="radio" name="demo-radio-1">
  <span class="ui-check-box"></span>
  Option two
</label>
<label class="ui-radio">
  <input type="radio" name="demo-radio-1">
  <span class="ui-check-box"></span>
  Option three
</label>
<label class="ui-radio">
  <input type="radio" name="demo-radio-disabled" disabled>
  <span class="ui-check-box"></span>
  Disabled
</label>

Radio colors

Show code
<label class="ui-radio">
  <input type="radio" name="demo-radio-color" checked>
  <span class="ui-check-box"></span>
  Primary
</label>
<label class="ui-radio success">
  <input type="radio" name="demo-radio-color-s" checked>
  <span class="ui-check-box"></span>
  Success
</label>
<label class="ui-radio danger">
  <input type="radio" name="demo-radio-color-d" checked>
  <span class="ui-check-box"></span>
  Danger
</label>
<label class="ui-radio warning">
  <input type="radio" name="demo-radio-color-w" checked>
  <span class="ui-check-box"></span>
  Warning
</label>

Radio sizes

Show code
<label class="ui-radio sm">
  <input type="radio" name="demo-radio-sz-s" checked>
  <span class="ui-check-box"></span>
  Small
</label>
<label class="ui-radio">
  <input type="radio" name="demo-radio-sz" checked>
  <span class="ui-check-box"></span>
  Default
</label>
<label class="ui-radio lg">
  <input type="radio" name="demo-radio-sz-l" checked>
  <span class="ui-check-box"></span>
  Large
</label>

Inputs

Text inputs

We'll never share your email.
Password must be at least 8 characters.
Show code
<div class="ui-field">
  <label>Name</label>
  <input class="ui-input" type="text" placeholder="Jane Doe">
</div>
<div class="ui-field">
  <label>Email</label>
  <input class="ui-input" type="email" placeholder="jane@example.com">
  <span class="ui-hint">We'll never share your email.</span>
</div>
<div class="ui-field">
  <label>Password (error state)</label>
  <input class="ui-input error" type="password" value="short">
  <span class="ui-error-text">Password must be at least 8 characters.</span>
</div>
<div class="ui-field">
  <label>Disabled</label>
  <input class="ui-input" type="text" value="Can't edit this" disabled>
</div>

Select & Textarea

Show code
<div class="ui-field">
  <label>Select</label>
  <select class="ui-select">
    <option>Option one</option>
    <option>Option two</option>
    <option>Option three</option>
  </select>
</div>
<div class="ui-field">
  <label>Textarea</label>
  <textarea class="ui-textarea" placeholder="Write something..."></textarea>
</div>

Inline checkboxes & radios

Show code
<div class="ui-row sm">
  <label class="ui-checkbox">
    <input type="checkbox" checked>
    <span class="ui-check-box"></span>
    Remember me
  </label>
  <label class="ui-checkbox">
    <input type="checkbox">
    <span class="ui-check-box"></span>
    Subscribe
  </label>
</div>
<div class="ui-row sm">
  <label class="ui-radio">
    <input type="radio" name="radio-demo" checked>
    <span class="ui-check-box"></span>
    Option A
  </label>
  <label class="ui-radio">
    <input type="radio" name="radio-demo">
    <span class="ui-check-box"></span>
    Option B
  </label>
</div>

Input sizes

Show code
<input class="ui-input sm" placeholder="Small input">
<input class="ui-input" placeholder="Default input">
<input class="ui-input lg" placeholder="Large input">

Sliders

Sizes & colors

Show code
<input type="range" class="ui-range sm" value="30">
<input type="range" class="ui-range" value="50">
<input type="range" class="ui-range lg success" value="70">
<input type="range" class="ui-range danger" value="80">
<input type="range" class="ui-range" value="40" disabled>

With value display

50
Show code
<input type="range" class="ui-range" value="50" min="0" max="100"
  oninput="document.getElementById('demo-range-val').textContent=this.value">
<span id="demo-range-val">50</span>

Panels

Default Panel

Default Panel

Panels group related content with a header, body, and optional footer. This is the default style with a subtle shadow.
Show code
<div class="ui-panel">
  <div class="ui-panel-header">
    <h3 class="ui-panel-title">Default Panel</h3>
    <div class="ui-panel-actions">
      <button class="ui-btn sm ghost secondary">Edit</button>
    </div>
  </div>
  <div class="ui-panel-body">
    Panels group related content with a header, body, and optional footer. This is the default style with a subtle shadow.
  </div>
  <div class="ui-panel-footer">
    <button class="ui-btn sm ghost secondary">Cancel</button>
    <button class="ui-btn sm">Save</button>
  </div>
</div>

Borderless Panel

Borderless Panel

The .borderless variant removes the border and relies solely on shadow for separation.
Show code
<div class="ui-panel borderless">
  <div class="ui-panel-header">
    <h3 class="ui-panel-title">Borderless Panel</h3>
  </div>
  <div class="ui-panel-body">
    The .borderless variant removes the border and relies solely on shadow for separation.
  </div>
</div>

Raised Panel

Raised Panel

This panel uses the .raised modifier for a more pronounced shadow, making it appear elevated from the page.
Show code
<div class="ui-panel raised">
  <div class="ui-panel-header">
    <h3 class="ui-panel-title">Raised Panel</h3>
  </div>
  <div class="ui-panel-body">
    This panel uses the .raised modifier for a more pronounced shadow, making it appear elevated from the page.
  </div>
</div>

Flat Panel

Flat Panel

The .flat variant removes the shadow entirely, keeping only the border for a minimal look.
Show code
<div class="ui-panel flat">
  <div class="ui-panel-header">
    <h3 class="ui-panel-title">Flat Panel</h3>
  </div>
  <div class="ui-panel-body">
    The .flat variant removes the shadow entirely, keeping only the border for a minimal look.
  </div>
</div>

Cards

Card variants

Simple card

A basic card with just a body. Good for small content blocks.

Featured

With header

Cards can have a header section for labels or titles.

Elevated

Uses shadow instead of border for a lifted look.

Show code
<div class="ui-card">
  <div class="ui-card-body">
    <h4 class="ui-card-title">Simple card</h4>
    <p class="ui-card-text">A basic card with just a body. Good for small content blocks.</p>
  </div>
</div>

<div class="ui-card">
  <div class="ui-card-header">Featured</div>
  <div class="ui-card-body">
    <h4 class="ui-card-title">With header</h4>
    <p class="ui-card-text">Cards can have a header section for labels or titles.</p>
  </div>
  <div class="ui-card-footer">
    <button class="ui-btn sm ghost">Cancel</button>
    <button class="ui-btn sm">Save</button>
  </div>
</div>

<div class="ui-card elevated">
  <div class="ui-card-body">
    <h4 class="ui-card-title">Elevated</h4>
    <p class="ui-card-text">Uses shadow instead of border for a lifted look.</p>
  </div>
</div>

Badges, Tags & Alerts

Badges

Primary Secondary Success Danger Warning
Show code
<span class="ui-badge">Primary</span>
<span class="ui-badge secondary">Secondary</span>
<span class="ui-badge success">Success</span>
<span class="ui-badge danger">Danger</span>
<span class="ui-badge warning">Warning</span>

Badge styles

Solid Success Danger Warning
Outline Success Danger Warning
With dot Online Offline
Show code
<div class="ui-row sm">
  <span class="ui-badge solid">Solid</span>
  <span class="ui-badge solid success">Success</span>
  <span class="ui-badge solid danger">Danger</span>
  <span class="ui-badge solid warning">Warning</span>
</div>
<div class="ui-row sm">
  <span class="ui-badge outline">Outline</span>
  <span class="ui-badge outline success">Success</span>
  <span class="ui-badge outline danger">Danger</span>
  <span class="ui-badge outline warning">Warning</span>
</div>
<div class="ui-row sm">
  <span class="ui-badge dot">With dot</span>
  <span class="ui-badge dot success">Online</span>
  <span class="ui-badge dot danger">Offline</span>
</div>

Badge sizes

Small Default Large
Show code
<span class="ui-badge sm">Small</span>
<span class="ui-badge">Default</span>
<span class="ui-badge lg">Large</span>

Tags (dismissible)

Default Primary Success Danger Warning
Show code
<span class="ui-tag">Default <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>
<span class="ui-tag primary">Primary <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>
<span class="ui-tag success">Success <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>
<span class="ui-tag danger">Danger <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>
<span class="ui-tag warning">Warning <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>

Tag sizes

Small Default Large No close button
Show code
<span class="ui-tag sm">Small <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>
<span class="ui-tag">Default <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>
<span class="ui-tag lg">Large <button class="ui-tag-close" onclick="this.parentElement.remove()">&times;</button></span>
<span class="ui-tag">No close button</span>

Alerts

This is an informational alert.
Operation completed successfully.
Please review your changes before saving.
An error occurred while processing your request.
Show code
<div class="ui-alert">This is an informational alert.</div>
<div class="ui-alert success">Operation completed successfully.</div>
<div class="ui-alert warning">Please review your changes before saving.</div>
<div class="ui-alert danger">An error occurred while processing your request.</div>

Status Dots

Colors

Show code
<span class="ui-dot"></span>
<span class="ui-dot primary"></span>
<span class="ui-dot success"></span>
<span class="ui-dot danger"></span>
<span class="ui-dot warning"></span>

Sizes

Show code
<span class="ui-dot success sm"></span>
<span class="ui-dot success"></span>
<span class="ui-dot success lg"></span>

With text & pulse

Online
Recording
Away
Offline
Show code
<div class="ui-row sm"><span class="ui-dot success"></span> Online</div>
<div class="ui-row sm"><span class="ui-dot danger pulse"></span> Recording</div>
<div class="ui-row sm"><span class="ui-dot warning"></span> Away</div>
<div class="ui-row sm"><span class="ui-dot"></span> Offline</div>

Numbered Badge

On buttons

3 12 99+
Show code
<!-- Single digit = circle, multi-digit = pill -->
<span class="ui-badge-corner">
  <button class="ui-btn outline"><i class="bi bi-bell"></i> Notifications</button>
  <span class="ui-count">3</span>
</span>

<!-- Multi-digit: pill shape (default) -->
<span class="ui-badge-corner">
  <button class="ui-btn outline secondary"><i class="bi bi-envelope"></i> Mail</button>
  <span class="ui-count primary">12</span>
</span>

<span class="ui-badge-corner">
  <button class="ui-btn outline"><i class="bi bi-cart"></i> Cart</button>
  <span class="ui-count success">99+</span>
</span>

On icon buttons & corner positions

5 2 8
Show code
<!-- Top-right (default) -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline"><i class="bi bi-bell"></i></button>
  <span class="ui-count">5</span>
</span>

<!-- Top-left -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline secondary"><i class="bi bi-chat"></i></button>
  <span class="ui-count top-left primary">2</span>
</span>

<!-- Bottom-right -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline"><i class="bi bi-heart"></i></button>
  <span class="ui-count bottom-right success">8</span>
</span>

<!-- Dot-only (no number) -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline secondary"><i class="bi bi-gear"></i></button>
  <span class="ui-count dot"></span>
</span>

Color variants

3 3 3 3 3
Show code
<!-- danger (default) -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline"><i class="bi bi-bell"></i></button>
  <span class="ui-count">3</span>
</span>

<!-- primary -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline"><i class="bi bi-bell"></i></button>
  <span class="ui-count primary">3</span>
</span>

<!-- success -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline"><i class="bi bi-bell"></i></button>
  <span class="ui-count success">3</span>
</span>

<!-- warning -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline"><i class="bi bi-bell"></i></button>
  <span class="ui-count warning">3</span>
</span>

<!-- secondary -->
<span class="ui-badge-corner">
  <button class="ui-btn icon outline"><i class="bi bi-bell"></i></button>
  <span class="ui-count secondary">3</span>
</span>

Tooltips

Positions

Show code
<button class="ui-btn sm outline ui-tooltip" data-tooltip="Tooltip on top">Top</button>

<button class="ui-btn sm outline ui-tooltip bottom" data-tooltip="Tooltip on bottom">Bottom</button>

<button class="ui-btn sm outline ui-tooltip left" data-tooltip="Tooltip on left">Left</button>

<button class="ui-btn sm outline ui-tooltip right" data-tooltip="Tooltip on right">Right</button>

On different elements

Inbox ui.css
Show code
<button class="ui-btn icon sm ui-tooltip" data-tooltip="Edit this item">
  <i class="bi bi-pencil"></i>
</button>

<span class="ui-badge solid ui-tooltip" data-tooltip="5 new messages">Inbox</span>

<code class="ui-tooltip bottom" data-tooltip="Click to copy">ui.css</code>

Avatars

Sizes & types

S
AB
CD
EF
SQ
Show code
<div class="ui-avatar sm">S</div>
<div class="ui-avatar">AB</div>
<div class="ui-avatar lg">CD</div>
<div class="ui-avatar xl">EF</div>
<div class="ui-avatar square lg">SQ</div>

Status indicators

JD
AK
MR
LS
Show code
<div class="ui-avatar">JD<span class="ui-avatar-status online"></span></div>
<div class="ui-avatar">AK<span class="ui-avatar-status away"></span></div>
<div class="ui-avatar">MR<span class="ui-avatar-status busy"></span></div>
<div class="ui-avatar">LS<span class="ui-avatar-status offline"></span></div>

Avatar group

A
B
C
D
+3
Show code
<div class="ui-avatar-group">
  <div class="ui-avatar">A</div>
  <div class="ui-avatar">B</div>
  <div class="ui-avatar">C</div>
  <div class="ui-avatar">+3</div>
</div>

Accordions

Collapsible sections

What is this UI library?
A lightweight, CSS-first component library using custom properties for theming. No JavaScript framework required.
How do I customize colors?
Override the CSS custom properties (e.g., --ui-primary) on your root element, or use the theme configurator on this page.
Does it support dark mode?
Yes. Add data-theme="dark" to your <html> element, or use the system preference toggle.
Show code
<div class="ui-accordion">
  <details open>
    <summary>What is this UI library?</summary>
    <div class="ui-accordion-body">A lightweight, CSS-first component library using custom properties for theming. No JavaScript framework required.</div>
  </details>
  <details>
    <summary>How do I customize colors?</summary>
    <div class="ui-accordion-body">Override the CSS custom properties (e.g., --ui-primary) on your root element, or use the theme configurator on this page.</div>
  </details>
  <details>
    <summary>Does it support dark mode?</summary>
    <div class="ui-accordion-body">Yes. Add data-theme="dark" to your html element, or use the system preference toggle.</div>
  </details>
</div>

Tabs

Default tabs

This is the overview panel. Tabs organize content into separate views where only one is visible at a time.
Features include responsive design, dark mode support, and configurable colors via CSS custom properties.
Pricing plans are available for teams of all sizes. Contact us for enterprise options.
Show code
<div class="ui-tabs" id="demo-tabs-1">
  <div class="ui-tab-list">
    <button class="ui-tab active" onclick="switchTab('demo-tabs-1', 0)">Overview</button>
    <button class="ui-tab" onclick="switchTab('demo-tabs-1', 1)">Features</button>
    <button class="ui-tab" onclick="switchTab('demo-tabs-1', 2)">Pricing</button>
    <button class="ui-tab" disabled>Disabled</button>
  </div>
  <div class="ui-tab-panel active">This is the overview panel. Tabs organize content into separate views where only one is visible at a time.</div>
  <div class="ui-tab-panel">Features include responsive design, dark mode support, and configurable colors via CSS custom properties.</div>
  <div class="ui-tab-panel">Pricing plans are available for teams of all sizes. Contact us for enterprise options.</div>
</div>

<script>
function switchTab(tabsId, index) {
  const tabs = document.getElementById(tabsId);
  tabs.querySelectorAll('.ui-tab-list .ui-tab').forEach((t, i) => t.classList.toggle('active', i === index));
  tabs.querySelectorAll('.ui-tab-panel').forEach((p, i) => p.classList.toggle('active', i === index));
}
</script>

Pill tabs

Showing all items in the list.
Showing only active items.
Showing archived items.
Show code
<div class="ui-tabs" id="demo-tabs-2">
  <div class="ui-tab-list pills">
    <button class="ui-tab active" onclick="switchTab('demo-tabs-2', 0)">All</button>
    <button class="ui-tab" onclick="switchTab('demo-tabs-2', 1)">Active</button>
    <button class="ui-tab" onclick="switchTab('demo-tabs-2', 2)">Archived</button>
  </div>
  <div class="ui-tab-panel active">Showing all items in the list.</div>
  <div class="ui-tab-panel">Showing only active items.</div>
  <div class="ui-tab-panel">Showing archived items.</div>
</div>

<script>
function switchTab(tabsId, index) {
  const tabs = document.getElementById(tabsId);
  tabs.querySelectorAll('.ui-tab-list .ui-tab').forEach((t, i) => t.classList.toggle('active', i === index));
  tabs.querySelectorAll('.ui-tab-panel').forEach((p, i) => p.classList.toggle('active', i === index));
}
</script>

Boxed tabs

HTML provides the structure and content of a webpage.
CSS handles the visual presentation and layout.
JavaScript adds interactivity and dynamic behavior.
Show code
<div class="ui-tabs" id="demo-tabs-3">
  <div class="ui-tab-list boxed">
    <button class="ui-tab active" onclick="switchTab('demo-tabs-3', 0)">HTML</button>
    <button class="ui-tab" onclick="switchTab('demo-tabs-3', 1)">CSS</button>
    <button class="ui-tab" onclick="switchTab('demo-tabs-3', 2)">JavaScript</button>
  </div>
  <div class="ui-tab-panel active">HTML provides the structure and content of a webpage.</div>
  <div class="ui-tab-panel">CSS handles the visual presentation and layout.</div>
  <div class="ui-tab-panel">JavaScript adds interactivity and dynamic behavior.</div>
</div>

<script>
function switchTab(tabsId, index) {
  const tabs = document.getElementById(tabsId);
  tabs.querySelectorAll('.ui-tab-list .ui-tab').forEach((t, i) => t.classList.toggle('active', i === index));
  tabs.querySelectorAll('.ui-tab-panel').forEach((p, i) => p.classList.toggle('active', i === index));
}
</script>

Toasts

Variants & position

Show code
<script>
// Container is created on the fly per position — no HTML needed
function getToastContainer(position = 'bottom-right') {
  const id = `ui-toast-${position}`;
  let c = document.getElementById(id);
  if (!c) {
    c = document.createElement('div');
    c.id = id;
    c.className = `ui-toast-container ${position}`;
    document.body.appendChild(c);
  }
  return c;
}

// type: 'info' | 'success' | 'danger' | 'warning'
// position: 'bottom-right' | 'top-right' | 'top-left' | 'bottom-left' | 'top-center' | 'bottom-center'
function showToast(type, message, position) {
  const icons = {
    info: 'bi-info-circle', success: 'bi-check-circle',
    danger: 'bi-exclamation-circle', warning: 'bi-exclamation-triangle',
  };
  const toast = document.createElement('div');
  toast.className = `ui-toast ${type}`;
  toast.innerHTML = `
    <i class="ui-toast-icon bi ${icons[type]}"></i>
    <span class="ui-toast-body">${message}</span>
    <button class="ui-toast-close"
      onclick="this.closest('.ui-toast').remove()">&times;</button>`;
  getToastContainer(position).appendChild(toast);
  setTimeout(() => toast.parentNode && toast.remove(), 4000);
}

// Usage:
showToast('success', 'Changes saved!', 'top-right');
showToast('danger', 'Something went wrong.'); // defaults to bottom-right
</script>

Progress Bars

Sizes & colors

Show code
<div class="ui-progress sm"><div class="ui-progress-bar" style="width:25%"></div></div>
<div class="ui-progress"><div class="ui-progress-bar" style="width:50%"></div></div>
<div class="ui-progress lg"><div class="ui-progress-bar success" style="width:75%"></div></div>
<div class="ui-progress"><div class="ui-progress-bar danger" style="width:40%"></div></div>
<div class="ui-progress"><div class="ui-progress-bar warning" style="width:60%"></div></div>

Striped & animated

Show code
<div class="ui-progress">
  <div class="ui-progress-bar striped" style="width:55%"></div>
</div>

<div class="ui-progress">
  <div class="ui-progress-bar striped animated success" style="width:70%"></div>
</div>

With label

68%
Show code
<div class="ui-progress ui-progress-labeled">
  <div class="ui-progress-bar" style="width:68%">68%</div>
</div>

Skeletons

Loading placeholders

Show code
<div class="ui-skeleton heading"></div>
<div class="ui-skeleton text"></div>
<div class="ui-skeleton text" style="width:80%"></div>
<div class="ui-skeleton text" style="width:60%"></div>
<div class="ui-skeleton circle" style="width:3rem; height:3rem;"></div>
<div class="ui-skeleton rounded" style="width:8rem; height:5rem;"></div>

Card skeleton

Show code
<div class="ui-card">
  <div class="ui-skeleton" style="width:100%; aspect-ratio:16/9; border-radius:0;"></div>
  <div class="ui-card-body">
    <div class="ui-skeleton heading" style="margin-bottom:0.375rem;"></div>
    <div class="ui-skeleton text" style="margin-bottom:0.375rem;"></div>
    <div class="ui-skeleton text" style="width:70%"></div>
  </div>
</div>

Dialogs

Default dialog

Show code
<div class="ui-dialog-backdrop" id="demo-dialog">
  <div class="ui-dialog">
    <div class="ui-dialog-header">
      <h3 class="ui-dialog-title">Confirm action</h3>
      <button class="ui-dialog-close" onclick="closeDialog('demo-dialog')">&times;</button>
    </div>
    <div class="ui-dialog-body">
      <p style="margin:0;">Are you sure you want to proceed? This action cannot be undone.</p>
    </div>
    <div class="ui-dialog-footer">
      <button class="ui-btn ghost secondary" onclick="closeDialog('demo-dialog')">Cancel</button>
      <button class="ui-btn danger" onclick="closeDialog('demo-dialog')">Delete</button>
    </div>
  </div>
</div>

<script>
function openDialog(id) {
  document.getElementById(id).classList.add('open');
}

function closeDialog(id) {
  document.getElementById(id).classList.remove('open');
}

// Close on backdrop click
document.querySelectorAll('.ui-dialog-backdrop').forEach(backdrop => {
  backdrop.addEventListener('click', e => {
    if (e.target === backdrop) backdrop.classList.remove('open');
  });
});

// Close on Escape
document.addEventListener('keydown', e => {
  if (e.key === 'Escape') {
    document.querySelectorAll('.ui-dialog-backdrop.open').forEach(b => b.classList.remove('open'));
  }
});
</script>

Large dialog

Show code
<div class="ui-dialog-backdrop" id="demo-dialog-lg">
  <div class="ui-dialog lg">
    <div class="ui-dialog-header">
      <h3 class="ui-dialog-title">Edit profile</h3>
      <button class="ui-dialog-close" onclick="closeDialog('demo-dialog-lg')">&times;</button>
    </div>
    <div class="ui-dialog-body">
      <div class="ui-stack sm">
        <div class="ui-field">
          <label>Display name</label>
          <input class="ui-input" type="text" value="Jane Doe">
        </div>
        <div class="ui-field">
          <label>Bio</label>
          <textarea class="ui-textarea" placeholder="Tell us about yourself..."></textarea>
        </div>
        <div class="ui-field">
          <label>Role</label>
          <select class="ui-select">
            <option>Developer</option>
            <option>Designer</option>
            <option>Manager</option>
          </select>
        </div>
      </div>
    </div>
    <div class="ui-dialog-footer">
      <button class="ui-btn ghost secondary" onclick="closeDialog('demo-dialog-lg')">Cancel</button>
      <button class="ui-btn" onclick="closeDialog('demo-dialog-lg')">Save changes</button>
    </div>
  </div>
</div>

<script>
function openDialog(id) {
  document.getElementById(id).classList.add('open');
}

function closeDialog(id) {
  document.getElementById(id).classList.remove('open');
}
</script>

Native <dialog> element

Show code
<dialog class="ui-dialog" id="native-dialog">
  <div class="ui-dialog-header">
    <h3 class="ui-dialog-title">Native Dialog</h3>
    <button class="ui-dialog-close" onclick="closeNativeDialog()">&times;</button>
  </div>
  <div class="ui-dialog-body">
    <p style="margin:0;">This uses the native &lt;dialog&gt; element with showModal(). It gets a browser-provided backdrop and focus trapping for free.</p>
  </div>
  <div class="ui-dialog-footer">
    <button class="ui-btn" onclick="closeNativeDialog()">Close</button>
  </div>
</dialog>

<script>
// Open with showModal() for browser-native focus trapping + backdrop
document.getElementById('native-dialog').showModal();

function closeNativeDialog() {
  document.getElementById('native-dialog').close();
}

// Close on backdrop click
document.getElementById('native-dialog').addEventListener('click', e => {
  const d = e.currentTarget;
  const rect = d.getBoundingClientRect();
  if (e.clientX < rect.left || e.clientX > rect.right ||
      e.clientY < rect.top  || e.clientY > rect.bottom) {
    d.close();
  }
});
</script>

Layout Utilities

Stack & Row

.ui-stack

Item 1
Item 2
Item 3

.ui-row

Tag 1 Tag 2 Tag 3
Show code
<div class="ui-panel flat">
  <div class="ui-panel-header"><h3 class="ui-panel-title">.ui-stack</h3></div>
  <div class="ui-panel-body">
    <div class="ui-stack sm">
      <div class="ui-alert">Item 1</div>
      <div class="ui-alert">Item 2</div>
      <div class="ui-alert">Item 3</div>
    </div>
  </div>
</div>
<div class="ui-panel flat">
  <div class="ui-panel-header"><h3 class="ui-panel-title">.ui-row</h3></div>
  <div class="ui-panel-body">
    <div class="ui-row sm">
      <span class="ui-badge">Tag 1</span>
      <span class="ui-badge secondary">Tag 2</span>
      <span class="ui-badge success">Tag 3</span>
    </div>
  </div>
</div>

Color Configuration

Override via CSS custom properties

Show code
<!-- Include the stylesheet -->
<link rel="stylesheet" href="src/ui.css">

<!-- Override colors via CSS custom properties -->
<style>
/* Use :root for the page, or :host inside a Shadow DOM component. */
:root {
  --ui-primary: #7c5cbf;
  --ui-primary-hover: #6a4daa;
  --ui-primary-active: #5a4195;
  --ui-primary-light: #f3effa;

  --ui-danger: #e85d75;
  --ui-success: #2cb87a;

  --ui-bg: #ffffff;
  --ui-text: #1a1d26;
  --ui-border: #e0e4ea;
  --ui-radius: 8px;
}
</style>

Dark Mode

Toggle with data-theme attribute

Set data-theme="dark" on <html>. The library includes a full set of dark-appropriate variables.

Show code
<!-- Enable dark mode via data attribute -->
<html data-theme="dark">

<!-- Toggle with JavaScript -->
<script>
function toggleDarkMode() {
  const html = document.documentElement;
  const isDark = html.getAttribute('data-theme') === 'dark';
  html.setAttribute('data-theme', isDark ? '' : 'dark');
}

// Or detect system preference
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
  document.documentElement.setAttribute('data-theme', 'dark');
}
</script>

Confirm action

Are you sure you want to proceed? This action cannot be undone.

Edit profile

Native Dialog

This uses the native <dialog> element with showModal(). It gets a browser-provided backdrop and focus trapping for free.

ui.css

Loading...