- name
- oat-css
- description
- Our preferred CSS framework — ultra-lightweight, semantic HTML UI library (~8KB). Style web UIs with semantic HTML and minimal classes. Override with app-level SCSS only when necessary.
- license
- MIT
- authors
- SpinSpire Team
# Oat CSS
Oat is an ultra-lightweight (~8KB min+gz), zero-dependency, semantic HTML/CSS/JS UI library by [Kailash Nadh](https://nadh.in) (5k+ stars on [GitHub](https://github.com/knadh/oat)). It styles native HTML elements out of the box — no classes needed for basic UIs. Dynamic components use WebComponents with minimal JS.
**Philosophy:** Semantic tags and attributes are styled contextually without classes, forcing best practices and reducing markup class pollution. Only reach for custom CSS when Oat's defaults don't cover your use case.
## Installation
### npm (SvelteKit, Vite, etc.)
```
bun add @knadh/oat
```
In your app entry or root SCSS:
```scss
@import '@knadh/oat/oat.min.css';
```
Import the JS for dynamic components (dialog, dropdown, tabs, toast, tooltip, sidebar):
```ts
import '@knadh/oat/oat.min.js';
```
Or selectively import individual files from `@knadh/oat/css/` and `@knadh/oat/js/`.
### CDN
```html
<link rel="stylesheet" href="https://unpkg.com/@knadh/oat/oat.min.css">
<script src="https://unpkg.com/@knadh/oat/oat.min.js" defer></script>
```
## Core Principle
**Use semantic HTML. Oat styles elements based on their tag and ARIA attributes, not CSS classes.**
```html
<!-- ❌ Class-heavy approach you DON'T need with Oat -->
<div class="card">
<div class="card-header">
<h3 class="card-title">Title</h3>
</div>
<div class="card-body">
<p>Content</p>
</div>
<div class="card-footer">
<button class="btn btn-primary">Save</button>
</div>
</div>
<!-- ✅ Semantic HTML — Oat styles this automatically -->
<article class="card">
<header>
<h3>Title</h3>
</header>
<p>Content</p>
<footer>
<button>Save</button>
</footer>
</article>
```
## When to Add Custom CSS/SCSS
Only override when:
1. **Brand colors** — redefine CSS variables in `:root` (see Theming below)
2. **Layout** — use Oat's `.hstack`, `.vstack`, `.container`/`.row`/`.col-*` grid, or add your own
3. **Complex compositions** — recipes like stats cards, split buttons, form cards
4. **Custom animations or interactions** — Oat doesn't ship opinionated transitions beyond the basics
Every Oat component below is purely semantic HTML. No custom CSS needed.
## Components
### Typography
```html
<h1>Heading 1</h1> <h2>Heading 2</h2> <h3>Heading 3</h3>
<p>Paragraph with <strong>bold</strong>, <em>italic</em>, and <a href="#">a link</a>.</p>
<pre><code>code block</code></pre>
<blockquote>Blockquote</blockquote>
<hr>
<ul><li>List item</li></ul>
<ol><li>Ordered item</li></ol>
```
### Button
`<button>` is styled by default. Use `data-variant` for semantics, `.outline`/`.ghost` for style, `.small`/`.large` for size.
```html
<button>Primary</button>
<button data-variant="secondary">Secondary</button>
<button data-variant="danger">Danger</button>
<button class="outline">Outline</button>
<button class="ghost">Ghost</button>
<button class="small">Small</button>
<button class="large">Large</button>
<button disabled>Disabled</button>
<a href="#" class="button">Link as button</a>
```
Button group:
```html
<menu class="buttons">
<li><button class="outline">Left</button></li>
<li><button class="outline">Center</button></li>
<li><button class="outline">Right</button></li>
</menu>
```
### Card
```html
<article class="card">
<header>
<h3>Card Title</h3>
<p>Description</p>
</header>
<p>Content here.</p>
<footer class="hstack">
<button class="outline">Cancel</button>
<button>Save</button>
</footer>
</article>
```
### Alert
Use `role="alert"` with optional `data-variant` (`success`, `warning`, `error`).
```html
<div role="alert" data-variant="success">
<strong>Success!</strong> Your changes have been saved.
</div>
<div role="alert" data-variant="warning">
<strong>Warning!</strong> Please review before continuing.
</div>
<div role="alert">
<strong>Info</strong> This is a default alert.
</div>
<div role="alert" data-variant="error">
<strong>Error!</strong> Something went wrong.
</div>
```
### Form
Wrap inputs in `<label data-field>` for proper styling. Input groups use `<fieldset class="group">`.
```html
<form>
<label data-field>
Name
<input type="text" placeholder="Enter your name" />
</label>
<label data-field>
<input type="checkbox" /> I agree
</label>
<label data-field>
<input type="checkbox" role="switch" checked> Toggle
</label>
<fieldset class="hstack">
<legend>Preference</legend>
<label><input type="radio" name="pref"> A</label>
<label><input type="radio" name="pref"> B</label>
</fieldset>
<fieldset class="group">
<input type="text" placeholder="Search" />
<button>Go</button>
</fieldset>
<div data-field="error">
<label>Email</label>
<input type="email" aria-invalid="true" value="bad" />
<div class="error" role="status">Invalid email.</div>
</div>
</form>
```
### Dialog (modal)
Uses native `<dialog>` with `commandfor`/`command` attributes (zero JS required).
```html
<button commandfor="my-dialog" command="show-modal">Open</button>
<dialog id="my-dialog" closedby="any">
<form method="dialog">
<header><h3>Title</h3></header>
<div><p>Content</p></div>
<footer>
<button commandfor="my-dialog" command="close" class="outline">Cancel</button>
<button value="confirm">Confirm</button>
</footer>
</form>
</dialog>
```
### Dropdown
Uses `<ot-dropdown>` WebComponent + native Popover API.
```html
<ot-dropdown>
<button popovertarget="menu" class="outline">Options ▾</button>
<menu popover id="menu">
<button role="menuitem">Profile</button>
<button role="menuitem">Settings</button>
<hr>
<button role="menuitem">Logout</button>
</menu>
</ot-dropdown>
```
### Tabs
Uses `<ot-tabs>` WebComponent.
```html
<ot-tabs>
<div role="tablist">
<button role="tab">Account</button>
<button role="tab">Password</button>
</div>
<div role="tabpanel"><h3>Account Settings</h3></div>
<div role="tabpanel"><h3>Password Settings</h3></div>
</ot-tabs>
```
### Table
```html
<div class="table">
<table>
<thead><tr><th>Name</th><th>Status</th></tr></thead>
<tbody>
<tr><td>Alice</td><td><span class="badge" data-variant="success">Active</span></td></tr>
</tbody>
</table>
</div>
```
### Badge
```html
<span class="badge">Default</span>
<span class="badge" data-variant="success">Success</span>
<span class="badge" data-variant="danger">Danger</span>
<span class="badge" data-variant="warning">Warning</span>
<span class="badge outline">Outline</span>
```
### Accordion
Native `<details>`/`<summary>`.
```html
<details>
<summary>What is Oat?</summary>
<p>Oat is a minimal, semantic-first UI library.</p>
</details>
<details name="group">
<summary>Grouped</summary>
</details>
```
### Progress & Meter
```html
<progress value="60" max="100"></progress>
<meter value="0.8" min="0" max="1" low="0.3" high="0.7" optimum="1"></meter>
```
### Spinner
```html
<div aria-busy="true"></div>
<div aria-busy="true" data-spinner="large"></div>
<button aria-busy="true" disabled>Loading</button>
<div aria-busy="true" data-spinner="large overlay">Content dims</div>
```
### Skeleton
```html
<div role="status" class="skeleton line"></div>
<div role="status" class="skeleton box"></div>
```
### Avatar
```html
<figure data-variant="avatar" aria-label="Jane Doe">
<img src="/avatar.svg" alt="" />
</figure>
<figure data-variant="avatar" aria-label="Oat">
<abbr title="Jane Doe">OT</abbr>
</figure>
```
### Sidebar
```html
<div data-sidebar-layout>
<aside data-sidebar>
<nav><ul><li><a href="#" aria-current="page">Home</a></li></ul></nav>
</aside>
<main>Content</main>
</div>
<!-- With top nav -->
<body data-sidebar-layout>
<nav data-topnav>
<button data-sidebar-toggle aria-label="Menu">☰</button>
<span>App</span>
</nav>
<aside data-sidebar>...</aside>
<main>...</main>
</body>
```
### Toast
```js
ot.toast('Saved!', 'Success', { variant: 'success' })
GitHubで見る