🌳
Oak v1.0
UI Component Library

Build faster with
zero overhead.

Drop two files into any project and get a complete, production-ready component system. No npm, no bundler, no framework lock-in.

HTML <link href="src/oak.css">  +  <script src="src/oak.js">
~9KBCSS gzipped
~3KBJS gzipped
28+Components
0Dependencies
Auto dark mode 80+ CSS tokens WCAG 2.1 AA Keyboard navigable Semantic HTML Native Web Components CSS Layers MIT License

Installation

Start Here

Two tags. That's the whole install story.

index.html
<!DOCTYPE html>
<html>
<head>
  <!-- Oak CSS — in <head> -->
  <link rel="stylesheet" href="src/oak.css">
</head>
<body>

  <button>Hello Oak</button>

  <!-- Oak JS — before </body> -->
  <script src="src/oak.js"></script>
</body>
</html>
CSS only? The JS file is only needed for interactive components: <oak-tabs>, <oak-dropdown>, <oak-accordion>, <oak-sidebar>, and oak.toast(). Everything else is pure CSS.

Buttons

Component

All <button> elements and <a class="btn"> links are styled by default. Variants use data-variant.

Variants
<button>Primary</button>
<button data-variant="secondary">Secondary</button>
<button data-variant="outline">Outline</button>
<button data-variant="ghost">Ghost</button>
<button data-variant="danger">Danger</button>
<button data-variant="success">Success</button>
Sizes, States & Groups
<button class="btn-sm">Small</button>
<button class="btn-lg">Large</button>
<button disabled>Disabled</button>
<button aria-busy="true">Loading</button>
<div class="btn-group">...</div>

Forms

Component

All native controls styled automatically. Wrap in [data-field] for error states and helper text.

Field controls
We'll never share your email.
Only letters, numbers, and underscores.
<div data-field>
  <label for="email">Email</label>
  <input id="email" type="email">
  <span data-hint>Helper text.</span>
</div>
<!-- Error state -->
<div data-field="error">
  <input aria-invalid="true">
  <span class="field-error">Error msg.</span>
</div>
Checkboxes, radios & switch
<label><input type="checkbox"> Accept</label>
<!-- Switch -->
<label>
  <input type="checkbox" role="switch" checked>
  Notifications
</label>
Input group
https://
<div class="input-group">
  <span class="input-addon">https://</span>
  <input type="text">
</div>

Cards

Component

Surface containers with optional card-header, card-body, and card-footer slots.

Card anatomy

Project Alpha

Q1 performance

Live

Revenue up 24% from last month. 1,200 new users onboarded.

Completion74%
JD
Jane Doe
Product Designer
<div class="card">
  <div class="card-header"><h3>Title</h3></div>
  <div class="card-body">...</div>
  <div class="card-footer">...</div>
</div>
<!-- Hover lift -->
<div class="card card-hover">...</div>

Badges & Chips

Component

Status indicators and removable filter tags.

Badges
Default Secondary Outline Active Pending Error Info
<span class="badge badge-success badge-dot">Active</span>
<span class="badge badge-danger">Error</span>
<span class="badge badge-outline">Outline</span>
Chips
Design Engineering Product Marketing
<span class="chip chip-active">Active</span>
<span class="chip">
  Label <button class="chip-remove">×</button>
</span>

Alerts

Component

Inline feedback using role="alert" and data-variant.

All variants
Trial ends in 3 days.
Upgrade now to keep access to all features.
Deployment complete.
Version 3.2.1 is now live in production.
Storage at 90%.
Delete old files or upgrade your plan.
Payment method expired.
Update billing to avoid service interruption.
<div role="alert" data-variant="success">
  <span class="alert-icon">...svg...</span>
  <div>
    <div class="alert-title">Done!</div>
    <div class="alert-desc">It worked.</div>
  </div>
</div>
<!-- variants: info | success | warning | danger -->

Tabs

Web Component

<oak-tabs> handles ARIA, keyboard nav (←→), and panel visibility automatically.

Pill tabs

Revenue up 24% vs. last month. Active users grew by 1,200 — the strongest month this quarter.

Deep-dive into funnel drop-offs, session duration, and feature engagement across cohorts.

Manage API keys, webhooks, team members, and billing preferences.

<oak-tabs>
  <div role="tablist">
    <button role="tab">Tab 1</button>
    <button role="tab">Tab 2</button>
  </div>
  <div role="tabpanel">Content 1</div>
  <div role="tabpanel">Content 2</div>
</oak-tabs>
Line tabs — add class="tabs-line" to tablist

Manage your profile, display name, and notification preferences.

View invoices, update payment methods, and manage subscription.

Change password, enable two-factor auth, view login history.

Connect third-party services and manage API keys.

<div role="tablist" class="tabs-line">...</div>

Modals

Component

Native <dialog> with CSS animations and backdrop blur. Wire triggers with commandfor — no JS needed.

Sizes
<button commandfor="my-modal" command="show-modal">Open</button>

<dialog id="my-modal">
  <div class="dialog-header"><h2>Title</h2></div>
  <div class="dialog-body">...</div>
  <div class="dialog-footer">
    <button commandfor="my-modal" command="close" data-variant="outline">Cancel</button>
    <button>Confirm</button>
  </div>
</dialog>
<!-- sizes: dialog-sm | (default) | dialog-lg | dialog-full -->

Confirm delete

This action cannot be undone. Are you sure?

Edit Profile

Update your display name and preferences.

Terms of Service

Please read carefully before continuing.

1. License

Oak is released under the MIT license. Free for personal and commercial use.

2. Contributions

All contributors agree to license their work under MIT terms.

3. Warranty

Oak is provided "as is" without warranty of any kind.

Toasts

JS API

Programmatic notifications via oak.toast(). Icons, 6 placements, pause-on-hover, and auto-dismiss included.

Live demo
// variants: success | warning | danger | info
oak.toast('Saved!', 'Title', { variant: 'success' });

// placement + custom duration
oak.toast('Done!', undefined, {
  variant:   'info',
  placement: 'bottom-center',  // top/bottom + left/center/right
  duration:  6000                // 0 = no auto-dismiss
});

oak.toast.clear();  // dismiss all

Accordion

Web Component

Wraps native <details>. Add exclusive to allow only one open at a time.

exclusive mode
What is Oak UI?
A zero-dependency HTML + CSS component library. Drop in two files — no build tool, no npm, no framework required.
How do I customize the theme?
Override any of the 80+ CSS custom properties on :root. Change --primary to rebrand everything instantly.
Is dark mode automatic?
Yes. Oak uses CSS light-dark() which follows the user's system preference with zero JavaScript.
What browsers are supported?
All modern evergreen browsers. Chrome 123+, Firefox 120+, Safari 17.5+. A polyfill handles the dialog API in older Safari.
<oak-accordion exclusive>
  <details open>
    <summary>Question</summary>
    <div class="accordion-body">Answer.</div>
  </details>
</oak-accordion>

Tables

Component
Hoverable
NameRoleStatusJoined
JD
Jane Doe
Designer Active Jan 2024
AB
Alex Brown
Engineer Away Mar 2024
SC
Sam Chen
Product Offline Jun 2024
<div class="table-wrap">
  <table class="hoverable">...</table>
</div>
<!-- also: class="striped" -->

Progress & Meter

Component
Progress bars
Storage85%
Active users62%
Uptime99%
Error rate (animated)6%
<progress value="85" max="100"></progress>
<progress class="progress-success" value="99" max="100"></progress>
<progress class="progress-warning progress-lg" value="85" max="100"></progress>
<progress class="progress-danger progress-striped" value="6" max="100"></progress>

Avatars

Component
Sizes, colors & groups
AB
JD
MK
SC
!
JD
AB
SK
+4
<div class="avatar">JD</div>
<div class="avatar avatar-lg avatar-success"></div>
<div class="avatar-group">
  <div class="avatar">A</div>
  <div class="avatar">+3</div>
</div>

Misc

Component
Tooltips
plain text
<button data-tooltip="Tooltip text">Hover</button>
<button data-tooltip="Below" data-tooltip-placement="bottom">Below</button>
Skeletons & Spinners
<div class="skeleton" role="status" style="height:1rem;width:100%"></div>

<div class="spinner"></div>
<div class="spinner spinner-lg spinner-success"></div>
Breadcrumbs, divider & KBD
or continue with email
Search: K Save: CtrlS Close: Esc
<nav aria-label="breadcrumb navigation">
  <ol><li><a href="#">Home</a></li><li>Current</li></ol>
</nav>
<div class="divider">or</div>
<kbd></kbd> <kbd>K</kbd>

Theming

Customization

Override CSS custom properties on :root to rebrand completely. No SASS, no config files.

Custom theme
:root {
  /* Brand — cascades everywhere */
  --primary:            #7c3aed;
  --primary-foreground: #ffffff;
  --primary-muted:      rgba(124, 58, 237, 0.1);

  /* Typography */
  --font-sans: 'Geist', system-ui, sans-serif;

  /* Sharper corners */
  --radius-md: 3px;
  --radius-lg: 6px;

  /* Force dark mode always */
  color-scheme: dark;
}
TokenPurposeLight default
--primaryBrand — buttons, links, focus rings
#2a5af5
--backgroundPage background
#ffffff
--foregroundBody text
#111118
--cardCard / panel surface
#ffffff
--borderBorders and dividers
#e2e2ec
--muted-foregroundSecondary text
#6b6b80
--success / --warning / --dangerSemantic status colorsGreen / Amber / Red
--font-sansBody typefacesystem-ui, sans-serif
--radius-mdDefault border radius0.5rem