An article
Long-form content goes in an <article>. An <aside> inside it becomes a callout:
A tiny, no-build CSS library that makes plain semantic HTML look clean and modern. One file. No classes required. Themeable with CSS variables, with dark mode built in.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tagbrush@1/tagbrush.min.css">
Plain CSS. No PostCSS, no bundler, no config. Drop in a <link> and you're done.
Headings, forms, tables, buttons and code blocks are styled out of the box. Write HTML, not class soup.
Colors, fonts, spacing and radius are semantic CSS custom properties. Override a few to make it yours.
Everything lives in a @layer, so your own CSS always wins. No !important, no specificity battles.
Follows the visitor's system setting automatically, or force it with data-theme="dark" on any element.
About 7 KB gzipped, with zero dependencies and zero JavaScript.
Import it once in your layout and every page picks it up. Astro, Next.js, React, Vue, Nuxt, Angular, SvelteKit, or a plain static site.
Apache 2.0 licensed. Fork it, tweak it, ship it.
Every component on this page reads from a handful of CSS variables. Change them here and the whole page updates live, then copy the CSS into your site or share a link to your theme. Hover colors, focus rings, and button text are derived from --color-primary automatically: buttons switch between white and black text, and links are adjusted to stay readable.
TagBrush.css follows the visitor's system preference. Use the switcher at the top of the page, or set data-theme on any element to force a scheme for just that part of the page:
Always light, whatever the system setting.
Always dark, whatever the system setting.
Everything below is plain HTML with no classes, styled entirely by TagBrush.css.
Body text is set in your system font with a comfortable line height. It supports links, bold, italics and inline code.
Inline elements are covered too: highlighted text, keyboard shortcuts like Ctrl + K, CSS abbreviations, H2O, E = mc2, sample output like Build succeeded, and small print.
Edits show up as removed and inserted text, outdated text is muted, a definition stands out, and inline quotes
get curly quote marks. is an <output>.
Wrap them in <hgroup> and the subtitle is muted automatically.
Kovir LabsBlockquotes are great for callouts, notes, and quotes worth highlighting.
// Code blocks scroll horizontally when they overflow, and highlighted
// code from Prism, highlight.js, Hugo, Jekyll, or Shiki gets theme colors
function greet(name) {
console.log(`Hello, ${name}!`);
return 42;
}
Lists inside <nav> become a horizontal row. Mark the current page with aria-current="page":
Label a <nav> "Breadcrumb" and its list gets separators:
Use <menu> for a toolbar of actions:
Long-form content goes in an <article>. An <aside> inside it becomes a callout:
<figure> to add a caption.Set aria-busy="true" while something loads. It shows a spinner and tells screen readers to wait:
Wrap buttons in <div role="group"> to lay them out in a row. It works for inline forms too:
Meters turn green, amber, or red based on their low, high and optimum attributes:
A native, accessible collapsible section with no JavaScript. Great for FAQs.
Neighboring <details> join into an accordion. Give them the same name so only one opens at a time:
Nope. Just write the HTML.
No. The browser handles opening and closing.
Yes, and with screen readers.
Native popover. Opened with the popovertarget attribute, no JavaScript needed. Click outside or press Esc to close.
A <section> of two or more <article>s becomes a grid of cards, with no classes. Headings and paragraphs in the section span the full width:
A list of posts on a home page.
Plans, products, or pricing tiers.
Anything you'd show side by side.
Dashboards and admin pages need no classes either. A <dl> of <div>s becomes stat tiles, a <header> with a heading and a button puts them on one row, and <search> lays out filters. An <aside> next to <main> becomes a sidebar layout.
A few optional classes cover the layouts almost every site needs: .grid for responsive columns, .card for boxed content, and role="group" for rows of buttons.
Cards sit in a .grid that wraps to one column on small screens.
Set --grid-min-column on a grid to change when it wraps.
--card-padding and --card-radius adjust every card at once.
| Variable | Default | Used for |
|---|---|---|
--color-primary | #2563eb | Links, buttons, focus states |
--color-surface | light gray, tinted by the primary | Code, blockquotes, cards |
--font-family-base | system-ui, … | All body text |
--border-radius | 0.375rem | Buttons, inputs, code |
| See the README for the full list. | ||
Use the CDN, or download tagbrush.css and host it yourself.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tagbrush@1/tagbrush.min.css">
<header><nav><strong>My site</strong> <a href="/about">About</a></nav></header>
<main>
<h1>Hello, world</h1>
<p>It already looks good.</p>
<button>Click me</button>
</main>
<footer>© 2026 Me</footer>
No classes needed: the content is centered and the footer stays at the bottom of short pages. Or start from starter.html, a complete page to copy.
<style>
:root {
--color-primary: #10b981;
--font-family-base: "Inter", sans-serif;
--border-radius: 0.5rem;
}
</style>
Because TagBrush.css lives in its own cascade layer, any rule you write wins, even a plain button { … } selector. No !important needed.