Discovering Oat UI: A Tiny CSS Library That Gets Out of Your Way
I was looking for a way to trim down my frontend stack — not switch to a new framework, not add another build step, just something I could drop into a project and have it look decent without writing a hundred utility classes. That’s when I came across Oat UI.
My first reaction was skepticism. Can a UI library really cover the basics — dialogs, forms, tabs, tables — in under 10KB? I opened the demo page and spent about ten minutes clicking through.
What Even Is Oat UI?
Oat is an ultra-lightweight, semantic HTML + CSS UI library with zero dependencies. No Node.js toolchain. No build step. No framework requirement. You just include two files and start writing HTML.
- The total weight? 6KB CSS + 2.2KB JS, minified and gzipped. That’s the whole thing.
- What makes it genuinely different is how it styles things. Rather than asking you to apply class names to every element, Oat styles native HTML elements and ARIA attributes directly. A
<button>looks like a button. A<dialog>works like a dialog. An element withrole=”alert”gets styled as an alert. You write semantic HTML, and the library just makes it look good
Why You Should Actually Consider Using It
Most UI libraries today are built around JavaScript ecosystems. They need npm, a bundler, a framework, and often a specific version of Node. They come with hundreds of dependencies, breaking changes every few months, and a learning curve that takes days to get through.
Get Pratik Dev’s stories in your inbox
Join Medium for free to get updates from this writer.
Oat’s author put it directly on the homepage — this library was born out of frustration with exactly that. If you’ve ever had a UI library break your project after an update, or spent an afternoon just getting a component library configured correctly, you’ll understand the appeal.
Here’s why Oat is worth considering:
- It’s genuinely tiny. 8KB total is smaller than most favicon files. This matters a lot in embeddable widgets, lightweight dashboards, or any project where every kilobyte affects load time.
- It uses CSS and ARIA the way they were meant to be used. Semantic HTML elements are styled out of the box.
- Zero dependencies. There is no dependency tree to audit, no lockfile conflicts, no ecosystem to keep up with. It’s just CSS and a small JS file for the few components (like dropdowns and tabs) that need behavior.
- Dark mode is automatic. It reads from
prefers-color-scheme— nothing to configure.
Getting Started
There’s no installation required. Just add two lines to your 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>That’s it. You can find the full usage guide at here.
A Real HTML Example
Here’s a small but complete HTML page using Oat — a simple card with a form inside it:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Oat UI Example</title>
<link rel="stylesheet" href="https://unpkg.com/@knadh/oat/oat.min.css">
<script src="https://unpkg.com/@knadh/oat/oat.min.js" defer></script>
</head>
<body>
<main>
<article>
<header>
<h2>Create Account</h2>
<p>Fill in your details below.</p>
</header>
<section>
<label for="name">Full name</label>
<input type="text" id="name" placeholder="Jane Doe" required />
<label for="email">Email</label>
<input type="email" id="email" placeholder="jane@example.com" required />
<label for="role">Role</label>
<select id="role">
<option>Developer</option>
<option>Designer</option>
<option>Manager</option>
</select>
</section>
<footer>
<button type="submit">Create Account</button>
<button type="button" class="secondary">Cancel</button>
</footer>
</article>
<!-- A simple alert -->
<div role="alert" class="success">Account created successfully.</div>
<!-- A native dialog -->
<dialog id="confirm-dialog">
<header><h3>Confirm Action</h3></header>
<p>Are you sure you want to continue?</p>
<footer>
<button onclick="document.getElementById('confirm-dialog').close()">Close</button>
</footer>
</dialog>
<button onclick="document.getElementById('confirm-dialog').showModal()">
Open Dialog
</button>
</main>
</body>
</html>Notice there are almost no custom classes. The card is just an <article>. The alert uses role=”alert”. The dialog is a native <dialog>element. Oat styles all of it.
How Customization Works
Oat uses CSS variables for theming. You override a handful of variables to change colors, spacing, border radius, and more. There’s a full guide at here.
:root {
--color-primary: #2563eb;
--radius: 0.5rem;
--font-body: 'Inter', sans-serif;
}What Works Really Well
After using it across a few small projects, a few components stand out:
- Dialog — The native
<dialog>element is notoriously tricky to style cross-browser. Oat handles it cleanly, including the backdrop and focus behavior. - Form elements — Inputs, selects, checkboxes, and radio buttons look consistent across browsers without any extra markup. This alone saves a lot of time.
- Table — Styled, responsive-friendly, and doesn’t require wrapper divs or special classes.
- Tabs (Web Component) — Works out of the box, keyboard-navigable, and doesn’t need any JavaScript from your side.
- Toast — Small, non-blocking, and sensible defaults. You call a function, it shows up.
A Few Things to Know Before Using It
Oat is still pre-v1. The author is upfront about this on the usage page — breaking changes are possible until it hits 1.0. So it’s better suited right now for personal projects, internal tools, or prototypes rather than large production apps where stability is critical.
- Because it styles semantic elements directly, it can sometimes conflict with existing CSS if you’re dropping it into a project that already has styles. Starting fresh or in an isolated scope works best.
- Also, the component set covers most common needs but isn’t exhaustive. If you need complex data grids, date pickers, or multi-step wizards, you’ll need to build those yourself or combine Oat with something else.
Where It Makes the Most Sense
- Internal tools and admin dashboards where you want things to look decent fast
- Server-rendered apps (Laravel, Rails, Django, Go templates) where a JS framework would be overkill
- Embeddable widgets where bundle size matters
- Prototypes and side projects where you want zero setup friction
- Projects where accessibility defaults are important but a full design system isn’t justified
Quick Setup Checklist
- Add the CDN CSS and JS links to your HTML
- Write semantic HTML — use native elements where possible (
<button>,<dialog>,<input>) - Use ARIA roles (
role=”alert”,role=”button”) to get styled variants - Override CSS variables if you need custom colors or radius
- Check components for component-specific markup patterns
- Check recipes for common layout and pattern examples
Closing Thoughts
Oat UI is a direct reaction to how bloated the frontend tooling world has become. It doesn’t try to replace React or compete with Tailwind — it occupies a different space entirely. If your project outputs HTML and you want it to look reasonable with minimal effort and zero toolchain overhead, it’s genuinely worth trying.
Have you tried Oat or a similar minimal CSS library? Drop a comment with what you’ve been using for lightweight projects.









