UI Kit

A standalone, framework-agnostic toolkit built with CSS custom properties and vanilla JS. No build tools required.

Setup
File Structure & CSS Entry Points Quick Start Design Tokens & Theming
Components
Buttons Cards Forms Tables Lists Progress Bar Log Terminal Dropdowns Drawers Modals Drawing Canvas Icons Tabs Badges Status Indicators Toasts Toggle Switch Collapsible / Accordion Empty State Grid Cards Tooltips Fade-In Animation Resize Handle Skip Link Button Sizes Navbar Avatar Timeline Spinner Button Group Alerts Kbd Code Dividers Fieldset Toolbar Stepper Sidebar Nav Stats Drag Handle Aspect Ratio Breadcrumb Pagination Scrollbar Skeleton Chat Picture-in-Picture Layout & App Shell Utilities & Colour Helpers
JavaScript
JavaScript API
File Structure & CSS Entry Points

The kit ships as flat files you copy into your project. No npm, no build step.

ui-kit/ tokens.css CSS custom properties (dark/light themes) base.css Box-sizing reset, body defaults, utilities components.css Aggregator: imports all 49 component files components/ buttons.css .btn, .btn-primary, .btn-secondary, ... cards.css .card, .card-header forms.css .form-row, .control-row, .feature-row drawers.css .drawer, .side-handle, .side-panel dropdowns.css .ui-dropdown, .ui-dropdown-item tables.css .ui-table, .ui-table-sticky progress.css .progress-area, .progress-bar log-terminal.css .log-terminal, .log-entry lists.css .ui-list, .ui-list-row modals.css .modal-overlay, .modal canvas.css .ui-canvas, .ui-canvas-clear icons.css .icon, .icon-spin layout.css .app, .app-topbar, .split-layout, ... theme-toggle.css .ui-theme-toggle (FAB) ui-kit.css Full entry point (tokens + base + components) ui-kit-core.css Minimal entry point (tokens + base only) icons.js 40+ Font Awesome icons as UIKit.ICONS ui-kit.js Behaviour helpers (theme, drawer, dropdown, ...) theme-bootstrap.js Prevents flash-of-wrong-theme (FOWT)
Option A — Full (all components)
<link rel="stylesheet" href="ui-kit/ui-kit.css">
Option B — Core + individual components
<link rel="stylesheet" href="ui-kit/ui-kit-core.css">
<link rel="stylesheet" href="ui-kit/components/buttons.css">
<link rel="stylesheet" href="ui-kit/components/cards.css">
<!-- only import what you need -->
Quick Start

Minimal boilerplate to get a page running with the full kit, theme toggle, and FOWT prevention.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <script src="ui-kit/theme-bootstrap.js"></script>
  <link href="https://fonts.googleapis.com/css2?family=Atkinson+Hyperlegible:wght@400;700&display=swap"
        rel="stylesheet">
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
        rel="stylesheet">
  <link rel="stylesheet" href="ui-kit/ui-kit.css">
</head>
<body>

  <!-- your content -->

  <button id="theme-toggle" class="ui-theme-toggle"></button>
  <script src="ui-kit/icons.js"></script>
  <script src="ui-kit/ui-kit.js"></script>
  <script>
    UIKit.initThemeToggle(document.getElementById("theme-toggle"));
  </script>
</body>
</html>
Design Tokens & Theming

All colours come from CSS custom properties in tokens.css. Dark is the default; add data-theme="light" to <html> for light mode. Use the theme toggle FAB (bottom-right) to switch live.

Surfaces
--bg
--surface
--surface2
--surface-muted
--surface-hl
Text
--text
--text-secondary
--text-muted
--text-inverse
Accents
--accent
--accent-hover
--accent-teal
--accent-olive
--accent-brown
--accent-dark
Semantic & Borders
--success
--warn
--danger
--border
--border-focus
Usage in CSS
/* Use tokens as CSS custom properties */
.my-panel {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text);
}
.my-panel:focus {
  border-color: var(--border-focus);
  box-shadow: 0 0 0 3px var(--focus-ring);
}
Buttons

Base .btn with variant modifiers. All share consistent sizing, font, and disabled states.

Variants
<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-icon">...</button>
Disabled & Loading
<button class="btn btn-primary" disabled>Disabled</button>
<button class="btn btn-primary btn-loading" disabled>Training...</button>
With icons
<button class="btn btn-primary">
  UIKit.ICONS.play + " Train"
</button>
Cards

Surface-coloured panels with border. Use .card-header for a title + action row. Stack cards with automatic collapsed borders.

Card with header

Model Configuration

Configure training parameters and hyperparameters for the selected model.

<div class="card">
  <div class="card-header">
    <h2>Model Configuration</h2>
    <button class="btn btn-secondary">Reset</button>
  </div>
  <p>Content here...</p>
</div>
Stacked cards (collapsed borders)

Input

Output

Logs

Forms

Three form patterns: .form-row (label+input grid), .control-row (select+buttons), and .feature-row (inline labelled inputs).

Form rows inside a card

Configuration

<div class="card-form">
  <div class="form-row">
    <label>Model</label>
    <select>...</select>
  </div>
  <div class="form-row">
    <label>Epochs</label>
    <input type="number" value="100">
  </div>
</div>
Control row (select + action buttons)
<div class="control-row">
  <select>...</select>
  <button class="btn btn-primary">Load</button>
  <button class="btn btn-icon">...</button>
</div>
Feature row (inline labelled inputs)
<div class="feature-row">
  <div class="feature-label">
    Sepal Length
    <input class="feature-input" type="number" value="5.1">
  </div>
  <!-- more inputs... -->
  <button class="btn btn-primary predict-row-btn">Predict</button>
</div>
Tables

Two variants: .ui-table (simple) and .ui-table-sticky (sticky headers for scrollable data). Wrap in .ui-table-wrap for bordered container.

Simple table
Model Accuracy F1 Score Status
Random Forest 96.7% 0.965 Ready
SVM (RBF) 94.2% 0.940 Ready
Logistic Regression 78.3% 0.771 Needs tuning
Decision Tree 65.1% 0.632 Overfitting
<div class="ui-table-wrap">
  <table class="ui-table">
    <thead><tr>
      <th>Model</th>
      <th>Accuracy</th>
    </tr></thead>
    <tbody><tr>
      <td>Random Forest</td>
      <td><span class="acc-high">96.7%</span></td>
    </tr></tbody>
  </table>
</div>
Empty state
ModelAccuracyStatus
No models trained yet
Lists

Scrollable row-based lists with name, tag badge, and action buttons.

Saved Models

rf_iris_v3.pkl 96.7%
svm_wine_tuned.pkl 94.2%
nn_digits_experimental.pkl 88.1%
<div class="ui-list">
  <div class="ui-list-row">
    <span class="ui-list-name">rf_iris_v3.pkl</span>
    <span class="ui-list-tag">96.7%</span>
    <button class="btn btn-icon">...</button>
    <button class="btn btn-danger">...</button>
  </div>
</div>
Progress Bar

Minimal track + fill bar. Set width via inline style or JS. Add .hidden to .progress-area when inactive.

Training epoch 65 / 100
<div class="progress-area">
  <div class="progress-bar-wrap">
    <div class="progress-bar" style="width:65%"
         role="progressbar" aria-valuenow="65"></div>
  </div>
  <div class="status-text">Training epoch 65 / 100</div>
</div>

<!-- Update via JS: -->
bar.style.width = pct + "%";
Log Terminal

Monospace scrollable log area with colour-coded levels. Use UIKit.createLogger() to append entries via JS.

14:23:01Initialising model pipeline...
14:23:02Dataset loaded: iris.csv (150 samples, 4 features)
14:23:02Splitting data: 80% train, 20% test
14:23:03Training complete in 1.2s
14:23:03Low feature importance detected for feature 2
14:23:04Validation error: class imbalance detected (ratio 3:1)
14:23:04Applying SMOTE oversampling...
14:23:05Retraining complete. Accuracy: 96.7%
<div class="log-terminal" role="log" aria-live="polite" id="log"></div>

<script>
  var log = UIKit.createLogger(document.getElementById("log"));
  log("Dataset loaded", "ok");    // green
  log("Low importance", "warn");  // amber
  log("Validation error", "err"); // red
  log("Processing...");             // default
</script>
Drawers

Collapsible side panels with a vertical handle + chevron. Click the handle to toggle.

Click the handle to open/close
Datasets
iris.csv150
wine.csv178
digits.csv1797
Main content area
<div class="drawer drawer-left" id="drawer">
  <div class="side-panel side-panel-left">
    <div class="side-panel-header">
      <div class="side-panel-title">Datasets</div>
    </div>
    <!-- panel content -->
  </div>
  <button class="side-handle side-handle-left" id="handle">
    UIKit.ICONS.chevron
    <span>Datasets</span>
  </button>
</div>

<script>
  UIKit.initDrawer(
    document.getElementById("drawer"),
    document.getElementById("handle")
  );
</script>
Modals

Overlay + centred dialog. Use .hidden on the overlay to toggle visibility. Combine with UIKit.onEscape() for keyboard dismissal.

Inline demo (normally position: fixed)
<div class="modal-overlay" id="modal">
  <div class="modal">
    <div class="modal-header">
      <span class="modal-title">Confirm Delete</span>
      <button class="btn btn-icon">...</button>
    </div>
    <p>Are you sure?</p>
    <div class="modal-footer">
      <button class="btn btn-secondary">Cancel</button>
      <button class="btn btn-danger">Delete</button>
    </div>
  </div>
</div>

<script>
  // Toggle with .hidden class
  document.getElementById("modal").classList.toggle("hidden");
  // Close on Escape
  UIKit.onEscape(function() { ... });
</script>
Drawing Canvas

Black canvas with border, crosshair cursor, and an overlay clear button. Designed for digit/gesture drawing inputs.

Draw something above, then click Clear
<div class="canvas-area">
  <div class="canvas-wrap">
    <canvas class="ui-canvas" width="200" height="120" id="canvas"></canvas>
    <button class="ui-canvas-clear">Clear</button>
  </div>
  <div class="canvas-hint">Draw a digit</div>
</div>
Icons

40+ icons via Font Awesome 6 Free. Available as UIKit.ICONS.name strings or via UIKit.icon("name"). Add .icon-spin for animation.

Full icon library
// Insert an icon via innerHTML
el.innerHTML = UIKit.ICONS.play;

// Or use the helper (same result)
el.innerHTML = UIKit.icon("play");

// Combine with text
btn.innerHTML = UIKit.ICONS.play + " Train Model";

// Spinning icon (e.g. loading state)
el.innerHTML = UIKit.ICONS.spinner; // has .icon-spin built-in
Tabs

Horizontal tab bar. Add .active to the selected tab.

Default tabs
<div class="ui-tabs">
  <button class="ui-tab active">Overview</button>
  <button class="ui-tab">Metrics</button>
  <button class="ui-tab">Settings</button>
</div>
Badges

Inline label badges for tags, counts, and status indicators.

Variants
Default Accent Success Warning Danger
<span class="ui-badge">Default</span>
<span class="ui-badge ui-badge-accent">Accent</span>
<span class="ui-badge ui-badge-success">Success</span>
<span class="ui-badge ui-badge-warn">Warning</span>
<span class="ui-badge ui-badge-danger">Danger</span>
Status Indicators

Dot + label for showing connection, health, or process state.

Status variants
Connected Degraded Offline Idle
<span class="ui-status ui-status-ok">
  <span class="ui-status-dot"></span>Connected
</span>
Toasts

Auto-dismissing notification toasts. Use UIKit.toast(msg, opts) from JS.

Trigger demos
UIKit.toast("Saved!", { type: "success" });
UIKit.toast("Warning", { type: "warn", duration: 5000 });
UIKit.toast("Error!", { type: "error" });
Toggle Switch

CSS-only toggle switch using a hidden checkbox + label.

Default toggle
<label class="ui-toggle">
  <input type="checkbox" checked>
  <span class="ui-toggle-track">
    <span class="ui-toggle-knob"></span>
  </span>
</label>
Collapsible / Accordion

Native <details>/<summary> with styled chevron. No JS required.

Collapsible sections
What frameworks does the kit support?

It's framework-agnostic — works with vanilla HTML, React, Vue, Svelte, or any templating system.

Do I need a build step?

No. Copy the files into your project and link the CSS. That's it.

Is it accessible?

Yes — Lighthouse 100 accessibility score with WCAG 2.1 AA contrast compliance.

<details class="ui-collapsible">
  <summary>Question here</summary>
  <p>Answer here</p>
</details>
Empty State

Placeholder for empty lists, tables, or search results.

Default empty state
No results found
Try adjusting your search or filters.
<div class="ui-empty">
  <div class="ui-empty-title">No results found</div>
  <div class="ui-empty-desc">Try adjusting your search.</div>
</div>
Grid Cards

Responsive two-column card grid with border-collapse and tag pills.

Card grid
Protein Kernel
GPU-accelerated molecular dynamics simulation engine.
CUDA Python
Nonogram Solver
Constraint-propagation puzzle solver with web UI.
JS Canvas
CV Editor
Live-preview resume builder with PDF export.
HTML CSS
UI Kit
This component library you're looking at right now.
CSS Vanilla JS
<div class="ui-grid">
  <div class="ui-grid-card">
    <div class="ui-grid-title">Title</div>
    <div class="ui-grid-desc">Description</div>
    <div class="ui-grid-tags">
      <span class="ui-grid-tag">Tag</span>
    </div>
  </div>
</div>
Tooltips

Pure CSS tooltips via the data-tooltip attribute. No JS required.

Hover for tooltip
Notifications
<button data-tooltip="Save your work">Hover me</button>
Fade-In Animation

Scroll-triggered reveal. Add .ui-fade-in and call UIKit.initFadeIn(). Respects prefers-reduced-motion.

Usage
<div class="ui-fade-in">Fades in on scroll</div>

<script>
  UIKit.initFadeIn(); // observes all .ui-fade-in elements
</script>
Resize Handle

Styled drag handles for split-pane layouts. Pair with UIKit.initResize().

Vertical & horizontal handles
Left
Right
<div class="ui-resize-handle ui-resize-v"></div> <!-- vertical -->
<div class="ui-resize-handle ui-resize-h"></div> <!-- horizontal -->
Button Sizes

Compact button variants for toolbars and dense UIs.

Size comparison
<button class="btn btn-primary">Default</button>
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary btn-xs">Extra Small</button>
Avatar

Circular or square profile images and initial placeholders.

Sizes & shapes
S
AP
LG
XL
<div class="ui-avatar ui-avatar-round">AP</div>
<div class="ui-avatar ui-avatar-lg">
  <img src="photo.jpg" alt="User">
</div>
Timeline

Chronological entry list for experience sections, changelogs, and history displays.

Experience entries
Senior EngineerAcme Corp
2023 – Present
  • Led migration to microservices architecture
EngineerStartupCo
2020 – 2023
  • Built real-time data pipeline
<div class="ui-timeline">
  <div class="ui-timeline-entry">
    <div class="ui-timeline-header">
      <span class="ui-timeline-title">Role</span>
      <span class="ui-timeline-date">2023</span>
    </div>
  </div>
</div>
Spinner

Border-based loading spinner. Standalone or inline with a text label.

Sizes & inline
Loading…
<div class="ui-spinner"></div>
<span class="ui-spinner-inline">
  <span class="ui-spinner ui-spinner-sm"></span> Loading…
</span>
Button Group

Segmented control for mode switching. Buttons share collapsed borders.

Segmented control
<div class="ui-btn-group">
  <button class="btn btn-secondary active">Grid</button>
  <button class="btn btn-secondary">List</button>
</div>
Alerts

Status messages and notification banners.

Variants
Default alert — neutral information.
Success — operation completed.
Warning — review before continuing.
Error — something went wrong.
<div class="ui-alert ui-alert-success">Saved!</div>
Kbd

Keyboard shortcut and key-press display.

Key combinations
Press Ctrl + S to save, or Esc to cancel.
<span class="ui-kbd">Ctrl</span> + <span class="ui-kbd">S</span>
Code

Inline code and code blocks with monospace font and terminal-style background.

Inline & block

Use npm install to add dependencies.

const UIKit = window.UIKit;
UIKit.toast("Hello!", { type: "success" });
<span class="ui-code">inline code</span>
<pre class="ui-code-block">code block</pre>
Dividers

Horizontal and vertical separators, with optional centered label.

Variants


Section Break
<hr class="ui-divider">
<div class="ui-divider-label">Section</div>
Fieldset

Form section groups with optional legend title.

Grouped form
Connection Settings
Form content goes here.
<fieldset class="ui-fieldset">
  <legend>Settings</legend>
  <!-- form content -->
</fieldset>
Toolbar

Horizontal action bar with groups, separators, spacers, and labels.

Grouped toolbar
Draft
<div class="ui-toolbar ui-toolbar-gap">
  <div class="ui-toolbar-group">...</div>
  <div class="ui-toolbar-separator"></div>
  <span class="ui-toolbar-spacer"></span>
  <span class="ui-toolbar-label">Draft</span>
</div>
Stepper

Numbered step indicator for wizards and multi-step flows.

Horizontal stepper
Upload
Configure
Deploy
<div class="ui-stepper">
  <div class="ui-step completed">Upload</div>
  <div class="ui-step-connector completed"></div>
  <div class="ui-step active">Configure</div>
  <div class="ui-step-connector"></div>
  <div class="ui-step">Deploy</div>
</div>
Stats

Key-value metric display for dashboards and summaries. Border-collapse row layout.

Stat row
Users 1,284 +12%
Revenue $42k -3%
Uptime 99.9%
<div class="ui-stat-row">
  <div class="ui-stat">
    <span class="ui-stat-label">Users</span>
    <span class="ui-stat-value">1,284</span>
    <span class="ui-stat-change ui-stat-change-up">+12%</span>
  </div>
</div>
Drag Handle

Visual grip indicator for sortable and draggable items. Includes ghost/chosen states for SortableJS.

Usage
<div class="ui-drag-handle"></div>
<!-- SortableJS classes: .ui-sortable-ghost, .ui-sortable-chosen -->
Aspect Ratio

Fixed-ratio containers for video, images, and embeds.

16:9 container
16:9
<div class="ui-ratio ui-ratio-16x9">
  <video>...</video>
</div>
<!-- Also: ui-ratio-4x3, ui-ratio-1x1, ui-ratio-21x9 -->
Pagination

Page navigation with collapsed borders and active state.

Page controls
<nav class="ui-pagination">
  <a class="ui-page">«</a>
  <a class="ui-page active">2</a>
  <a class="ui-page">3</a>
</nav>
Scrollbar

Custom scrollbar styling. Add ui-scrollbar to any scrollable container.

Usage
<div class="ui-scrollbar" style="overflow:auto; height:200px;">
  <!-- scrollable content -->
</div>
<!-- Also: ui-scrollbar-thin for 4px width -->
Skeleton

Loading placeholder animation. Respects prefers-reduced-motion.

Loading placeholders
<div class="ui-skeleton ui-skeleton-heading"></div>
<div class="ui-skeleton ui-skeleton-text"></div>
<div class="ui-skeleton ui-skeleton-text"></div>
<!-- Also: ui-skeleton-avatar, ui-skeleton-block -->
Chat

Message display container for chat and conversation UIs.

Chat messages
Hey, is the deploy ready?
Yes, just pushed to staging.
Alice joined the room
Great, let’s ship it.
<div class="ui-chat">
  <div class="ui-chat-messages">
    <div class="ui-chat-msg">Hello</div>
    <div class="ui-chat-msg ui-chat-msg-self">Hi!</div>
  </div>
  <div class="ui-chat-input">
    <input placeholder="Type...">
    <button>Send</button>
  </div>
</div>
Picture-in-Picture

Corner-positioned overlay for video previews and mini views.

Usage
<div style="position:relative;">
  <div class="ui-pip ui-pip-br ui-pip-sm">
    <video>...</video>
  </div>
</div>
<!-- Positions: ui-pip-tr, ui-pip-tl, ui-pip-br, ui-pip-bl -->
<!-- Sizes: ui-pip-sm, ui-pip-md, ui-pip-lg -->
Layout & App Shell

Full-viewport app shell with topbar, sidebar, main area, and optional split columns with drag-to-resize.

App shell structure
.app-topbar
.app-sidebar
.app-main
<div class="app">
  <div class="app-topbar">...</div>
  <div class="app-body">
    <div class="app-sidebar">...</div>
    <div class="app-main">...</div>
  </div>
</div>
Split layout with resize handle
<div class="split-layout" id="split">
  <div class="left-col" id="left">
    <!-- cards, forms -->
  </div>
  <div class="resize-handle resize-h" id="handle"></div>
  <div class="right-col">
    <!-- table, chart -->
  </div>
</div>

<script>
  UIKit.initResize(
    document.getElementById("handle"),
    document.getElementById("left"),
    document.getElementById("split"),
    { min: 200, "default": 300, key: "split-w" }
  );
</script>
Responsive breakpoints
1100px — Right column stacks below left; split layout goes vertical
 900px — Drawer handle hides; body scrolls; sidebar goes full-width
 600px — Feature inputs wrap to 50%; predict button goes full-width
Utilities & Colour Helpers
Utility classes
.hiddendisplay: none !important
.sr-only — Visually hidden, accessible to screen readers
.resize-dragging — Applied to <body> during drag-resize (disables text selection)
Colour helpers for data display
acc-high: 96.7%   acc-med: 78.3%   acc-low: 65.1%
conf-high: Ready   conf-low: Needs tuning
pred-label: Setosa
<span class="acc-high">96.7%</span>  <!-- green -->
<span class="acc-med">78.3%</span>   <!-- amber -->
<span class="acc-low">65.1%</span>   <!-- red -->
<span class="conf-high">Ready</span>  <!-- green -->
<span class="conf-low">...</span>     <!-- muted -->
<span class="pred-label">Setosa</span> <!-- bold accent -->
JavaScript API

Load icons.js first, then ui-kit.js. Everything lives on window.UIKit. Nothing auto-initialises — call only what you need.

Method Purpose Returns
initThemeToggle(el, opts?) Dark/light toggle with localStorage { setTheme(t), destroy() }
initDrawer(drawerEl, handleEl) Collapsible side drawer { open(), close(), toggle(), destroy() }
initDropdown(triggerEl, menuEl) Toggle menu + click-outside { open(), close(), destroy() }
onEscape(callback) Register Escape-key handler unsubscribe()
initResize(handle, target, container, opts?) Drag-to-resize split layout
createLogger(terminalEl, max?) Log terminal appender addLog(msg, level?)
toast(msg, opts?) Show auto-dismissing toast HTMLElement
dismissToast(el) Manually dismiss a toast
initFadeIn(scope?, opts?) Observe .ui-fade-in elements
ICONS Object of Font Awesome icon markup { play, pause, stop, ... }
icon(name, opts?) Get icon HTML by name string
theme-bootstrap.js (prevents flash-of-wrong-theme)
// Must be the FIRST <script> in <head>, before any CSS
<script src="ui-kit/theme-bootstrap.js"></script>

// It reads from localStorage and sets data-theme before first paint.
// Also syncs across tabs via the "storage" event.
// Exposes: window.__setTheme(t), window.__getTheme()