Sample panel
Delivery Live
v0.2.1 / 174 components / no build step
Stylesheets that make a page look finished. Written for small screens first, no build step and no tool to run, and you link only the pieces the page actually shows.
npm i @barebase/style
Or link a file straight from the page, with nothing installed at all.
Theme published
Both themes measured at AA.
Sample panel
Delivery Live
No script anywhere in this group. Every surface in it is a file linked in the head of this page, and the controls in it work.
01 / What it is
Every one of these is a thing the framework refuses to do rather than a feature it advertises.
This page loads no stylesheet of its own. Every rule you can see is bare.style styling bare.style, which is the fastest way to find out what a framework is missing.
02 / Size
Every number here comes from scripts/size.ts, which
compresses the real bytes. Run bun run size and check them.
All three are the delivered form: dist/, comments stripped,
gzip level 9 over one concatenated file. That is the only column comparable to another
framework's published figure, which is always its minified build.
| Bundle | Form | Files | Raw | gzip, one file | gzip, separate | brotli |
|---|---|---|---|---|---|---|
| Core only | delivered | 4 | 21,740 | 4,832 B | 5,669 | 4,023 |
| Core only | authored | 4 | 65,158 | 19,901 | 21,895 | 16,872 |
| Everything | delivered | 174 | 505,475 | 78,773 B | 136,975 | 50,421 |
| Everything | authored | 174 | 1,423,118 | 355,566 | 485,008 | 259,164 |
Two gzip columns because both are real delivery shapes. One file is a single link to a concatenated bundle. Separate is what per-element link tags over HTTP/2 cost, where each file is compressed on its own, and it is always the larger of the two.
03 / Agent cost
The styling lives in the stylesheet instead of in the class attribute, so there is far less markup to type. When the thing doing the typing is a language model billed by the token, less to type is less to pay.
Six fragments - a hero, a settings form, a table with a toolbar, a card grid, a modal and a row of dashboard tiles - written twice. Once in bare.style, once in the class lists Tailwind's own documentation produces for that component. The wording on the page is identical in both, so the only thing being compared is the styling.
| Counted as | Exact? | bare.style | Tailwind | Ratio |
|---|---|---|---|---|
| Characters | Exact | 5,796 | 11,992 | 2.1x |
| Token floor | Exact | 1,724 | 3,389 | 2.0x |
| Tokens | Estimated | 2,197 | 4,623 | 2.1x |
Counting exact tokens needs a 1.7 MB merge table from the model vendor, and shipping one inside a framework that argues against dependencies is not a trade worth making. So the last row is an estimate and says so. The middle row is not: it is the number of pieces the text splits into before any merging happens, which no real tokeniser can go below. All three land in the same place, which is the point of printing all three.
Run bun run token-cost to reproduce every figure above,
including the fragments themselves.
04 / Install
Copy src/ into the directory your site serves and link the
four core files plus whatever you use. Nothing to compile, nothing to configure, no
runtime.
Each file declares the shared layer order before its own rules, so these tags can go in any sequence. A component loaded later cannot outrank one loaded first by accident.
index.html
<!-- mandatory -->
<link rel="stylesheet" href="/css/core/reset.css">
<link rel="stylesheet" href="/css/core/tokens.css">
<link rel="stylesheet" href="/css/core/type.css">
<link rel="stylesheet" href="/css/core/base.css">
<!-- only what this page shows -->
<link rel="stylesheet" href="/css/layout/stack.css">
<link rel="stylesheet" href="/css/data/table.css">
<link rel="stylesheet" href="/css/forms/button.css">
05 / Rules
06 / Theme
Light is the default. A reader who has not chosen follows their operating system. A reader who has chosen keeps that choice even when the system says the opposite, and that is the part most implementations get wrong: source order alone does not achieve it, because a later media query still beats an equal-specificity class rule placed before it.
Two things make it airtight. The media query targets
:root:not(.theme-light), so a pinned light theme is never
matched rather than merely overridden afterwards. The pinned blocks are
:root.theme-light and
:root.theme-dark, which outrank the plain
:root default wherever they sit in the file.
The toggle in the bar above is currently following the system.
07 / Components
Every example in the documentation is a working component, and the markup shown under it is read out of that example rather than transcribed, so it cannot drift.