Pure CSS, JavaScript for progressive enhancement. Dark mode: add class="dark" to
<html> or use the included JS helper.
Override these RGB variables to customize your entire color theme. All colors, variants, and gradients are auto-generated.
:root {
--color-primary-rgb: 99, 102, 241;
--color-secondary-rgb: 236, 72, 153;
--color-tertiary-rgb: 245, 158, 11;
--color-background-rgb: 256, 256, 256;
--color-background-tint-rgb: 112, 154, 196;
--font-base-rgb: 9, 18, 31;
}
Auto-generated: --color-primary, --color-primary-400, --color-primary-600,
and all rgba() values throughout the framework.
Pro-tip: randoma11y.com has some great combinations! They don't just look good, but a high-enough contrast helps to make your site more accessible too!
Small labels for status, categories, or counts.
<span class="badge {style} {color} {size}">Text</span>
style: hollow | soft | gradient | hollow
gradient | (omit for filled)
color: primary | secondary | success |
warning | error | info | (omit for default)
size: sm | lg | (omit for default)
<span class="badge success">
<svg>...</svg>
Completed
</span>
A modern font pairing using Plus Jakarta Sans for headings and Inter for body text.
This is a regular paragraph with bold text, italic text, and a link. The body font is Inter, optimized for readability on screens with proper kerning and ligatures enabled.
You can also use animated gradient links for extra flair, or the secondary gradient variant for a different color scheme.
This is a lead paragraph. It's slightly larger and used for introductory text or important callouts that need more visual prominence.
This is small text, useful for captions, footnotes, or secondary information that shouldn't distract from the main content.
Design is not just what it looks like and feels like. Design is how it works.
Steve Jobs
Use inline code for short code snippets within text.
// Code block example
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet('World'));
Use Cmd + K to open the command palette.
<p class="lead">Larger intro text</p>
<a href="#" class="gradient">Gradient link</a>
<span class="text-muted">Muted</span>
<span class="font-semibold">Semibold</span>
link style: gradient | gradient secondary | (omit for
default)
weight: font-light | font-medium | font-semibold |
font-bold
Native <dl> elements for key-value displays.
<dl class="{layout}">
<dt>Label</dt>
<dd>Value</dd>
</dl>
layout: horizontal | bordered | (omit for stacked)
Notification banners with icons and animated gradients.
<div class="alert {style} {color} {size}">
<svg class="alert-icon">...</svg>
<div class="alert-content">
<div class="alert-title">Title</div>
<div class="alert-description">Message</div>
</div>
</div>
style: filled | hollow
color: success | warning | error | info
| primary | secondary
size: sm | lg | (omit for default)
Data tables with sorting, hover states, and responsive layouts.
| Name | Role | Status | |
|---|---|---|---|
| John Doe | john@example.com | Admin | Active |
| Jane Smith | jane@example.com | Editor | Pending |
| Metric | Value | Change |
|---|---|---|
| Page Views | 24,521 | +14.9% |
| Bounce Rate | 42.3% | +2.8% |
Resize browser to see rows stack on mobile.
| Name | Status | Actions | |
|---|---|---|---|
| John Doe | john@example.com | Active | |
| Jane Smith | jane@example.com | Pending |
<!-- Icon buttons -->
<button class="btn-icon primary"><svg>...</svg></button>
<button class="btn-icon danger"><svg>...</svg></button>
<!-- Action chips -->
<button class="action-chip">View</button>
<button class="action-chip primary">Approve</button>
<button class="action-chip danger">Reject</button>
style: striped | hollow | responsive | (omit for
default)
btn-icon variants: primary | danger | success |
sm
action-chip variants: primary | danger | success
spacing: compact | relaxed | (omit for default)
sortable header: add sorted and optionally desc to .th-content.sortable
responsive: use class="responsive" on table, and add data-label
to each <td> with its column name (e.g. data-label="Email")
Text fields with validation and style variants.
<input type="{type}" class="{style} {state}" placeholder="...">
type: text | email | password | number
| date | time | search | tel | url | file
| range
style: hollow | gradient | hollow secondary | gradient
secondary | (omit for default)
state: input-error | input-success | (omit for normal)
required: Add required attribute to the input and the label will automatically
show a required indicator
Consider these attributes for better UX:
autocomplete — Hints to browser what type of data field expects (name, email, cc-number, etc).
Enables autofill.
enterkeyhint — Changes mobile keyboard's enter key label (search, go, next, done, send).
Improves UX clarity.
inputmode — Controls which mobile keyboard appears (numeric, decimal, tel, email, url). More
specific than input type.
Dropdown menus with style variants.
<select class="{style}">
<option value="1">Option 1</option>
</select>
style: hollow | gradient | hollow secondary | gradient
secondary | (omit for default)
Searchable dropdown - type to filter options.
<input type="text" list="my-options" class="{style}" placeholder="Search...">
<datalist id="my-options">
<option value="Option 1">
<option value="Option 2">
</datalist>
style: hollow | gradient | hollow secondary | gradient
secondary | (omit for default)
Multi-line text input.
<textarea class="{style}" placeholder="..."></textarea>
style: hollow | gradient | hollow secondary | gradient
secondary | (omit for default)
Custom styled checkboxes.
<input type="checkbox" class="gradient">
<input type="checkbox" class="gradient secondary">
Variants: gradient | gradient secondary
Custom styled radio buttons.
<input type="radio" name="group" class="gradient">
<input type="radio" name="group" class="gradient secondary">
Variants: gradient | gradient secondary
iOS-style toggle switches.
<input type="checkbox" class="toggle {style} {size}">
style: gradient | secondary | gradient secondary |
(omit for default)
size: sm | (omit for default)
Disclosure controls for expandable content, Apple HIG compliant with smooth animations.
This content is revealed when the details element is opened. The chevron rotates smoothly and the content animates in.
You can put any content here - text, images, forms, or other components.
A smaller version for tighter layouts.
Content for the first section. Multiple details can be open at once.
Content for the second section.
Content for the third section.
<!-- Default -->
<details>
<summary>Click to expand</summary>
<div class="details-content">
<div class="details-content-inner">
<p>Your content here</p>
</div>
</div>
</details>
<!-- Compact -->
<details class="compact">...</details>
<!-- Accordion group -->
<div class="details-group">
<details>...</details>
<details>...</details>
</div>
variant: compact | flush | (omit for default)
group: wrap in details-group for accordion style
Native <dialog> element with accessible keyboard handling and focus trapping built-in.
Works without Javascript using the commandfor
attribute.
window.confirm() or
window.alert() for simple confirmations
<details> for progressive
disclosure without context loss
Use for simple confirmations following Apple HIG patterns.
<dialog id="my-modal" class="modal {size}">
<div class="modal-header">
<h3 class="modal-title">Title</h3>
<button class="modal-close" commandfor="my-modal" command="show-modal">✕</button>
</div>
<div class="modal-body">...</div>
<div class="modal-footer">
<button commandfor="my-modal" command="close">Cancel</button>
<button>Confirm</button>
</div>
</dialog>
size: sm | lg | (omit for default)
variant: compact for centered alert-style modals
Browsers have a built-in confirmation dialog when users try to navigate away from a page with unsaved changes. Use this instead of a custom modal — it's consistent across all sites and cannot be dismissed accidentally.
// Enable the warning when there are unsaved changes
window.addEventListener('beforeunload', (e) => {
if (hasUnsavedChanges) {
e.preventDefault();
e.returnValue = ''; // Required for Chrome/Edge
}
});
// Or use the helper function from framework.js:
const unsavedChanges = trackUnsavedChanges();
// Mark form as having changes
unsavedChanges.setDirty();
// Clear after saving
unsavedChanges.setClean();
// Check current state
if (unsavedChanges.isDirty()) { ... }
Note: Modern browsers show a generic message like "Changes you made may not be saved" — custom messages are ignored for security reasons.
Use gradients to communicate state changes and guide user attention.
Let users know a field is being updated. Click "Generate" to see it in action.
Removing the gradient abruptly looks jarring. Use easeOutGradient() for a polished transition.
<script src="js/framework.js"></script>
// Fade out smoothly
easeOutGradient(element);
// Need to run code after? It's a Promise:
await easeOutGradient(element);
doSomethingNext();
Add gradient to buttons during async operations. Users see something is happening.