A lightweight CSS component library with nested CSS and configurable colors.
<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>
<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>
<button class="ui-btn ghost">Primary</button> <button class="ui-btn ghost secondary">Secondary</button> <button class="ui-btn ghost danger">Danger</button>
<button class="ui-btn sm">Small</button> <button class="ui-btn">Default</button> <button class="ui-btn lg">Large</button>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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 class="ui-input sm" placeholder="Small input"> <input class="ui-input" placeholder="Default input"> <input class="ui-input lg" placeholder="Large input">
<div class="ui-dropdown" id="demo-dd-1">
<button class="ui-dropdown-toggle" onclick="toggleDropdown('demo-dd-1')">Actions</button>
<div class="ui-dropdown-menu">
<button class="ui-dropdown-item" onclick="toggleDropdown('demo-dd-1')"><i class="bi bi-pencil"></i> Edit</button>
<button class="ui-dropdown-item" onclick="toggleDropdown('demo-dd-1')"><i class="bi bi-files"></i> Duplicate</button>
<hr class="ui-dropdown-divider">
<button class="ui-dropdown-item" onclick="toggleDropdown('demo-dd-1')" style="color:var(--ui-danger)"><i class="bi bi-trash"></i> Delete</button>
</div>
</div>
<div class="ui-dropdown" id="demo-dd-2">
<button class="ui-dropdown-toggle" onclick="toggleDropdown('demo-dd-2')"><i class="bi bi-funnel"></i> Filter by status</button>
<div class="ui-dropdown-menu">
<span class="ui-dropdown-label">Status</span>
<button class="ui-dropdown-item active" onclick="this.classList.toggle('active')"><i class="bi bi-check-lg"></i> Active</button>
<button class="ui-dropdown-item" onclick="this.classList.toggle('active')"><i class="bi bi-clock"></i> Pending</button>
<button class="ui-dropdown-item" onclick="this.classList.toggle('active')"><i class="bi bi-archive"></i> Archived</button>
<hr class="ui-dropdown-divider">
<span class="ui-dropdown-label">Priority</span>
<button class="ui-dropdown-item" onclick="this.classList.toggle('active')"><i class="bi bi-flag"></i> High</button>
<button class="ui-dropdown-item" onclick="this.classList.toggle('active')"><i class="bi bi-flag"></i> Medium</button>
<button class="ui-dropdown-item" onclick="this.classList.toggle('active')"><i class="bi bi-flag"></i> Low</button>
</div>
</div>
<div class="ui-dropdown right" id="demo-dd-3">
<button class="ui-dropdown-toggle" onclick="toggleDropdown('demo-dd-3')"><i class="bi bi-sort-down"></i> Sort</button>
<div class="ui-dropdown-menu">
<button class="ui-dropdown-item active" onclick="selectDropdownItem(this)">Newest first</button>
<button class="ui-dropdown-item" onclick="selectDropdownItem(this)">Oldest first</button>
<button class="ui-dropdown-item" onclick="selectDropdownItem(this)">Name A–Z</button>
<button class="ui-dropdown-item" onclick="selectDropdownItem(this)">Name Z–A</button>
</div>
</div>
<script>
function toggleDropdown(id) {
const dd = document.getElementById(id);
document.querySelectorAll('.ui-dropdown.open').forEach(d => {
if (d.id !== id) d.classList.remove('open');
});
dd.classList.toggle('open');
}
// Close on outside click
document.addEventListener('click', e => {
if (!e.target.closest('.ui-dropdown')) {
document.querySelectorAll('.ui-dropdown.open').forEach(d => d.classList.remove('open'));
}
});
// Activate a single item (radio-style)
function selectDropdownItem(btn) {
btn.closest('.ui-dropdown-menu').querySelectorAll('.ui-dropdown-item').forEach(i => i.classList.remove('active'));
btn.classList.add('active');
}
</script>
<div class="ui-autocomplete" id="demo-ac-1">
<i class="bi bi-search ui-autocomplete-icon"></i>
<input class="ui-autocomplete-input" type="text" placeholder="Search countries..." oninput="filterAutocomplete('demo-ac-1')" onfocus="this.closest('.ui-autocomplete').classList.add('open')">
<div class="ui-autocomplete-menu">
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Australia</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Austria</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Brazil</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Canada</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Denmark</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Finland</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">France</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Germany</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Japan</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Norway</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Sweden</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">United Kingdom</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">United States</button>
<span class="ui-autocomplete-empty">No results found</span>
</div>
</div>
<div class="ui-autocomplete" id="demo-ac-2">
<i class="bi bi-person ui-autocomplete-icon"></i>
<input class="ui-autocomplete-input" type="text" placeholder="Assign to..." oninput="filterAutocomplete('demo-ac-2')" onfocus="this.closest('.ui-autocomplete').classList.add('open')">
<div class="ui-autocomplete-menu">
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)"><i class="bi bi-person-circle"></i> Alice Johnson</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)"><i class="bi bi-person-circle"></i> Bob Smith</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)"><i class="bi bi-person-circle"></i> Carol Williams</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)"><i class="bi bi-person-circle"></i> David Brown</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)"><i class="bi bi-person-circle"></i> Eve Davis</button>
<span class="ui-autocomplete-empty">No results found</span>
</div>
</div>
<script>
// Filter items as user types
function filterAutocomplete(id) {
const ac = document.getElementById(id);
const query = ac.querySelector('.ui-autocomplete-input').value.toLowerCase();
const items = ac.querySelectorAll('.ui-dropdown-item');
let visible = 0;
items.forEach(item => {
const match = item.textContent.toLowerCase().includes(query);
item.classList.toggle('hidden', !match);
if (match) visible++;
});
ac.querySelector('.ui-autocomplete-empty').style.display = visible === 0 ? 'block' : 'none';
ac.querySelectorAll('.ui-dropdown-item.focused').forEach(i => i.classList.remove('focused'));
ac.classList.add('open');
}
// Select an item and close
function pickAutocomplete(btn) {
const ac = btn.closest('.ui-autocomplete');
ac.querySelector('.ui-autocomplete-input').value = btn.textContent.trim();
ac.querySelectorAll('.ui-dropdown-item.focused').forEach(i => i.classList.remove('focused'));
ac.classList.remove('open');
}
// Keyboard: Arrow Up/Down to navigate, Enter to pick, Escape to close
document.addEventListener('keydown', e => {
const ac = e.target.closest('.ui-autocomplete');
if (!ac || !ac.classList.contains('open')) return;
const items = [...ac.querySelectorAll('.ui-dropdown-item:not(.hidden)')];
if (!items.length) return;
const current = ac.querySelector('.ui-dropdown-item.focused');
let idx = current ? items.indexOf(current) : -1;
if (e.key === 'ArrowDown') {
e.preventDefault();
if (current) current.classList.remove('focused');
idx = idx < items.length - 1 ? idx + 1 : 0;
items[idx].classList.add('focused');
items[idx].scrollIntoView({ block: 'nearest' });
} else if (e.key === 'ArrowUp') {
e.preventDefault();
if (current) current.classList.remove('focused');
idx = idx > 0 ? idx - 1 : items.length - 1;
items[idx].classList.add('focused');
items[idx].scrollIntoView({ block: 'nearest' });
} else if (e.key === 'Enter' && current) {
e.preventDefault();
pickAutocomplete(current);
} else if (e.key === 'Escape') {
ac.classList.remove('open');
}
});
// Close on outside click
document.addEventListener('click', e => {
if (!e.target.closest('.ui-autocomplete')) {
document.querySelectorAll('.ui-autocomplete.open').forEach(ac => ac.classList.remove('open'));
}
});
</script>
<div class="ui-autocomplete sm" id="my-ac-sm">
<i class="bi bi-search ui-autocomplete-icon"></i>
<input class="ui-autocomplete-input" type="text" placeholder="Small..." oninput="filterAutocomplete('my-ac-sm')" onfocus="this.closest('.ui-autocomplete').classList.add('open')">
<div class="ui-autocomplete-menu">
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Australia</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Brazil</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Canada</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">France</button>
<span class="ui-autocomplete-empty">No results found</span>
</div>
</div>
<div class="ui-autocomplete" id="my-ac">
<i class="bi bi-search ui-autocomplete-icon"></i>
<input class="ui-autocomplete-input" type="text" placeholder="Default..." oninput="filterAutocomplete('my-ac')" onfocus="this.closest('.ui-autocomplete').classList.add('open')">
<div class="ui-autocomplete-menu">
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Australia</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Brazil</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Canada</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">France</button>
<span class="ui-autocomplete-empty">No results found</span>
</div>
</div>
<div class="ui-autocomplete lg" id="my-ac-lg">
<i class="bi bi-search ui-autocomplete-icon"></i>
<input class="ui-autocomplete-input" type="text" placeholder="Large..." oninput="filterAutocomplete('my-ac-lg')" onfocus="this.closest('.ui-autocomplete').classList.add('open')">
<div class="ui-autocomplete-menu">
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Australia</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Brazil</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">Canada</button>
<button class="ui-dropdown-item" onclick="pickAutocomplete(this)">France</button>
<span class="ui-autocomplete-empty">No results found</span>
</div>
</div>
<script>
function filterAutocomplete(id) {
const ac = document.getElementById(id);
const query = ac.querySelector('.ui-autocomplete-input').value.toLowerCase();
const items = ac.querySelectorAll('.ui-dropdown-item');
let visible = 0;
items.forEach(item => {
const match = item.textContent.toLowerCase().includes(query);
item.classList.toggle('hidden', !match);
if (match) visible++;
});
ac.querySelector('.ui-autocomplete-empty').style.display = visible === 0 ? 'block' : 'none';
ac.classList.add('open');
}
function pickAutocomplete(btn) {
const ac = btn.closest('.ui-autocomplete');
ac.querySelector('.ui-autocomplete-input').value = btn.textContent.trim();
ac.classList.remove('open');
}
// Close on outside click
document.addEventListener('click', e => {
if (!e.target.closest('.ui-autocomplete')) {
document.querySelectorAll('.ui-autocomplete.open').forEach(ac => ac.classList.remove('open'));
}
});
</script>
<div class="ui-dropdown sm" id="my-dropdown-sm">
<button class="ui-dropdown-toggle" onclick="toggleDropdown('my-dropdown-sm')">Small</button>
<div class="ui-dropdown-menu">
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown-sm')">Option one</button>
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown-sm')">Option two</button>
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown-sm')">Option three</button>
</div>
</div>
<div class="ui-dropdown" id="my-dropdown">
<button class="ui-dropdown-toggle" onclick="toggleDropdown('my-dropdown')">Default</button>
<div class="ui-dropdown-menu">
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown')">Option one</button>
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown')">Option two</button>
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown')">Option three</button>
</div>
</div>
<div class="ui-dropdown lg" id="my-dropdown-lg">
<button class="ui-dropdown-toggle" onclick="toggleDropdown('my-dropdown-lg')">Large</button>
<div class="ui-dropdown-menu">
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown-lg')">Option one</button>
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown-lg')">Option two</button>
<button class="ui-dropdown-item" onclick="toggleDropdown('my-dropdown-lg')">Option three</button>
</div>
</div>
<script>
function toggleDropdown(id) {
const dd = document.getElementById(id);
document.querySelectorAll('.ui-dropdown.open').forEach(d => {
if (d.id !== id) d.classList.remove('open');
});
dd.classList.toggle('open');
}
document.addEventListener('click', e => {
if (!e.target.closest('.ui-dropdown')) {
document.querySelectorAll('.ui-dropdown.open').forEach(d => d.classList.remove('open'));
}
});
</script>
<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>
<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>
<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 variant removes the border and relies solely on shadow for separation.
<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 modifier for a more pronounced shadow, making it appear elevated from the page.
<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 variant removes the shadow entirely, keeping only the border for a minimal look.
<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>
A basic card with just a body. Good for small content blocks.
Cards can have a header section for labels or titles.
Uses shadow instead of border for a lifted look.
<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>
<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>
<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>
<span class="ui-badge sm">Small</span> <span class="ui-badge">Default</span> <span class="ui-badge lg">Large</span>
<span class="ui-tag">Default <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span> <span class="ui-tag primary">Primary <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span> <span class="ui-tag success">Success <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span> <span class="ui-tag danger">Danger <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span> <span class="ui-tag warning">Warning <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span>
<span class="ui-tag sm">Small <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span> <span class="ui-tag">Default <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span> <span class="ui-tag lg">Large <button class="ui-tag-close" onclick="this.parentElement.remove()">×</button></span> <span class="ui-tag">No close button</span>
<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>
<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>
<span class="ui-dot success sm"></span> <span class="ui-dot success"></span> <span class="ui-dot success lg"></span>
<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>
<!-- 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>
<!-- 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>
<!-- 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>
<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>
ui.css
<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>
<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>
<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>
<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>
--ui-primary) on your root element, or use the theme configurator on this page.data-theme="dark" to your <html> element, or use the system preference toggle.<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>
<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>
<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>
<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>
<ul class="ui-breadcrumb"> <li><a href="#">Home</a></li> <li><a href="#">Products</a></li> <li><a href="#">Category</a></li> <li>Current page</li> </ul>
<ul class="ui-breadcrumb"> <li><a href="#"><i class="bi bi-house"></i></a></li> <li><a href="#">Settings</a></li> <li><a href="#">Account</a></li> <li>Security</li> </ul>
<nav class="ui-pagination"> <button class="ui-page" disabled>‹</button> <button class="ui-page active">1</button> <button class="ui-page">2</button> <button class="ui-page">3</button> <span class="ui-page ellipsis">…</span> <button class="ui-page">12</button> <button class="ui-page">›</button> </nav>
<nav class="ui-pagination outline"> <button class="ui-page" disabled>‹</button> <button class="ui-page">1</button> <button class="ui-page active">2</button> <button class="ui-page">3</button> <button class="ui-page">4</button> <button class="ui-page">5</button> <button class="ui-page">›</button> </nav>
<nav class="ui-pagination sm"> <button class="ui-page" disabled>‹</button> <button class="ui-page active">1</button> <button class="ui-page">2</button> <button class="ui-page">3</button> <button class="ui-page">›</button> </nav> <nav class="ui-pagination">...</nav> <nav class="ui-pagination lg">...</nav>
<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()">×</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>
<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>
<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>
<div class="ui-progress ui-progress-labeled"> <div class="ui-progress-bar" style="width:68%">68%</div> </div>
<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>
<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>
<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')">×</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>
<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')">×</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>
<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()">×</button>
</div>
<div class="ui-dialog-body">
<p style="margin:0;">This uses the native <dialog> 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>
<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>
<!-- 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>
Set data-theme="dark" on <html>. The library includes a full set of dark-appropriate variables.
<!-- 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>
Are you sure you want to proceed? This action cannot be undone.