Pure CSS Components: the 2014 checkbox hacks next to today's native elements
:coffee: A set of common UI Components using just the power of CSS and without JavaScript.
At a glance
- What is it?
- Pure CSS Components is a documentation site that puts six UI components from 2014, built with hidden checkboxes and radio buttons, side by side with the same components built on details, dialog, popover and the newer CSS features, plus ten components that only exist natively now. It suits a front-end developer deciding whether to reach for a JavaScript library, and it is a poor fit if you want a component library you can install.
- Who is it for?
- Pure CSS Components fits a front-end developer who wants to understand what the platform now does for free before adding a dependency, since every exhibit pairs the old trick with the native replacement and states the real browser support.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 14 days ago.
- What is it written in?
- Mainly CSS, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A gallery of UI components built with no JavaScript at all
Pure CSS Components describes itself as a set of common UI components using the power of CSS and without JavaScript, and the site states the promise more bluntly: UI components built with HTML and CSS only, zero JavaScript, in 2014 and today.
The framing is the interesting part. This is not a component library you install and import. It is a documentation site, built with Astro and published on Netlify, where each component shows its HTML and its CSS so you can copy them. The description in the repository, a set of common UI components, reads like a package, but the repository itself is marked private, and there is no published npm package for the components themselves. What is published is the knowledge.
The idea has a history. In 2014, a modal, a carousel or a set of tabs meant a jQuery plugin, and this project built them with no JavaScript at all, storing their state in hidden checkboxes, radio buttons and the URL hash. The project says a lot of people shipped them to production. The original Stylus sources and zip downloads are still available in the v2.0.0 release, which is tagged as the 2014 original build, and the current site keeps those originals for historical reference.
The site states four principles, and they are the criteria the rest of the article is measured against. Zero JavaScript, not in the components and not on the site, working with JavaScript turned off. Honest support, meaning every native feature shows its real browser support. Progressive enhancement, with new features behind @supports so nothing breaks where they are missing. And accessible by default, where the native versions use real elements with focus, keyboard and screen reader support built in.
The last two are what separate the modern half of the project from a party trick. A CSS-only component that is not keyboard operable is a worse version of the library component it replaces.
Six components, two implementations each, side by side
The centre of the site is a table with three columns, the component, how it was done in 2014 and how HTML and CSS do it now, and each row links to a live exhibit on the page.
The carousel was radio inputs plus labels in 2014, and is now built with scroll-snap, ::scroll-button() and ::scroll-marker. The collapse was a hidden checkbox or radios, and is now details with a name attribute plus ::details-content. The dropdown was a hidden checkbox with :hover, and is now the Popover API with anchor positioning and interestfor. The modal was a hidden checkbox, and is now the dialog element with commandfor and @starting-style. The tab was radio inputs, and is now exclusive details with a name attribute laid out as tabs. The tooltip was :hover with an ::after pseudo-element, and is now popover="hint" with interestfor and anchor positioning.
Two things are worth pulling out of that list. The dialog element with commandfor and @starting-style is what makes a native modal behave like a modern one, including the entry animation, which a checkbox can never do. And interestfor appears twice, in the dropdown and the tooltip, which is the hint that the direction of travel is a single new CSS feature making a family of behaviours possible.
The dropdown and tooltip are also the two components where the 2014 versions were weakest. A tooltip driven by :hover is unavailable on touch, and a dropdown that closes when the pointer leaves is not a menu. The native versions use the platform's own transient and popover machinery, which is why the site argues the old versions are for history and the native ones are what you should use if you are building something today.
Ten components that could not have existed in 2014
The second half of the site covers components with no 2014 version at all, because no hidden input could fake them and until recently each one needed a script.
A custom select is built with appearance: base-select and ::picker(select). A switch and segmented control use the input switch attribute and :has(). Smarter forms use field-sizing: content and :user-invalid. A file tree is nested details elements. A filters drawer uses dialog with closedby and invoker commands. A sticky header uses scroll-state container queries. A scroll-spy table of contents uses scroll-target-group and :target-current. A reading progress bar uses scroll-driven animations. A radial menu uses sibling-index() and sibling-count(). A gallery uses cross-document view transitions.
Look at the shape of that list. Roughly half of it is CSS that reacts to scroll position, which is a category that simply did not exist as a CSS concern in 2014, when the equivalent was a scroll listener in JavaScript. The other half is platform behaviour that used to need a component library and now needs nothing.
The project is explicit that some of these features are new, and that every exhibit lists where it works today, with browsers that lack support getting a plain version that still works. That is the progressive enhancement principle applied at the level of individual components rather than at the level of the page, and it is the most transferable idea in the project: a component that degrades to a working plain version is not a component that degrades to nothing.
The born-native set is also where the accessibility argument gets its strongest, because the switch is a real input element, the file tree is real details elements with their built-in keyboard behaviour, and the drawer is a real dialog.
How the site is built, and how you run it locally
The site is an Astro project. The package.json names it css-components, marks it private and of type module, and gives it the title Pure CSS Components and the description A set of common UI Components using the power of CSS and without JavaScript. The package manager is pinned to pnpm at version 12.6.0, and the engines field requires node 22.12.0 or newer. There is a .nvmrc in the repository root, an astro.config.mjs, a pnpm-workspace.yaml, a pnpm-lock.yaml, a netlify.toml and a netlify/ directory.
The local workflow is two commands, and the documentation requires Node.js 22.12 or newer along with pnpm:
pnpm install
pnpm devThe three scripts that matter are listed in the readme. pnpm dev starts the dev server, pnpm build type-checks and builds to dist, and pnpm lint lints scripts and styles. The package.json fills in the details: dev runs astro dev, build runs astro build, preview runs astro preview, check runs astro check, and lint runs eslint together with stylelint over src for css and astro files, with a lint:fix variant that adds the --fix flag to both.
The dependency list is small and deliberate. Astro is the only runtime dependency, and the rest are fonts: Bricolage Grotesque, Source Serif 4 and IBM Plex Mono, all as variable or static fontsource packages. The devDependencies are the linting and type-checking toolchain, with eslint 10, stylelint 17, typescript around 6.0, the astro eslint plugin, eslint-plugin-astro, stylelint-config-standard and stylelint-config-html, plus postcss-html so stylelint can parse CSS inside Astro files. A separate stylelint.config.js sits at the root.
That toolchain tells you something about the project's priorities. Stylelint with the html config and postcss-html is there so the CSS inside .astro files is linted like any other CSS, which matters when the entire content of the site is stylesheets.
Where Pure CSS Components is the wrong thing to reach for
The first limitation is that it is not a library. There is no package to install, no import, no props, no theming API and no versioned component contract. You copy HTML and CSS into your project and then own it, which means a design change to a component is a change to every page that copied it. For a marketing site with a handful of static pages, that is a reasonable trade. For an application with forty screens, it is the beginning of your own component library, with none of the machinery.
The second is browser support, and the project is honest about it rather than hiding it, which is to its credit. The native versions depend on features that are still arriving: the popover attribute, interestfor, invoker commands, ::picker(select), the switch attribute, scroll-state container queries, sibling-index() and cross-document view transitions are all recent. A team supporting browsers from a few years ago will be reading support tables and writing fallbacks for each component, which is real work that a maintained component library would have done once.
The third is that the 2014 half is history, not a recommendation. The readme says so directly: if you are building something today, use the native versions. Which means the interesting part of the repository for a working developer is the modern half, and the 2014 half is there for comparison and for anyone who needs to support an environment where the native features are missing.
The fourth is that the no-JavaScript constraint cuts both ways. It is a strong design discipline and it makes the components work in a content pipeline with scripts stripped, in an email renderer, or in a hardened environment. It also removes the escape hatches. A modal that needs to be dismissed by a server response, a tab set that has to react to application state, a dropdown that opens on a keyboard shortcut: those are not in the vocabulary of the 2014 patterns, and while the native versions handle more of them, they are still declarative rather than programmable.
The fifth is the state of the project itself. The package version in the manifest is 3.0.0, but the only published release tag is v2.0.0, and the topic list still names boostrap among the tags. The site is a living document, which is the point of it, and the value is in reading it rather than in depending on it.
Editorial conclusion
Pure CSS Components fits a front-end developer who wants to understand what the platform now does for free before adding a dependency, since every exhibit pairs the old trick with the native replacement and states the real browser support. It is the wrong choice if you are looking for an installable component library, because the project is a documentation site whose code you copy by hand, and it is the wrong choice for a team that needs consistent behaviour across old browsers, since the native versions depend on features that are still landing. Before using any of it, open the components page, copy the HTML and CSS for the one you need, and check the support line on that exhibit, and note that the last push was on 2026-10-09 with the only published release tag being v2.0.0 from 2026-09-28, which carries the original 2014 Stylus sources.
Frequently asked questions
What is Pure CSS Components?
It is a documentation site of UI components built with HTML and CSS only, with no JavaScript in the components or on the site. Each component shows its HTML and CSS so you can copy them into your own project.
How does Pure CSS Components replace a JavaScript modal or dropdown?
The site shows both approaches side by side. The 2014 versions stored state in hidden checkboxes, radio buttons and the URL hash, while the modern versions use the dialog element with commandfor and @starting-style, and the Popover API with anchor positioning and interestfor.
How do I run Pure CSS Components locally?
You need Node.js 22.12 or newer and pnpm. Run pnpm install and then pnpm dev to start the dev server, with pnpm build to type-check and build to dist and pnpm lint to lint scripts and styles.
Which browsers support the native components in Pure CSS Components?
Each exhibit lists where it works today, and browsers without support get a plain version that still works. Newer features sit behind @supports so nothing breaks where they are missing.
What licence is Pure CSS Components released under?
MIT, credited to Felipe Fialho, with the licence text in license.md at the root of the repository.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/felipefialho-css-components)Was this useful?