Bits UI: headless Svelte components without the styling opinions
The headless components for Svelte.
At a glance
- What is it?
- An MIT-licensed primitive library for Svelte 5 that gives you behaviour, accessibility and state while leaving every pixel to your own component. Patch releases show a project paying close attention to focus management and floating element edge cases.
- Who is it for?
- Bits UI is the right choice when you want accessible component behaviour without adopting someone else's design system, particularly if you are on Svelte 5 and comfortable composing parts yourself rather than importing a finished dropdown. It is a poor fit if you want a battery-included theme, because nothing is styled and the documentation site is where the examples live, and the README itself is a page of credits and badges.
- 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 TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Primitives rather than a component library
The README describes Bits UI as the headless components for Svelte, and then makes the trade explicit in one sentence: flexible, unstyled and accessible primitives that provide the foundation for building your own high-quality component library.
That is a narrower promise than most libraries make, and it is the reason the project exists in this form. Nothing arrives with CSS attached. What you get is state management, keyboard handling, focus trapping, ARIA attributes and positioning behaviour, exposed as composable parts that you render inside your own markup. If you have ever used a component library and then fought it because the styling assumptions were wrong, this is the alternative shape.
The repository topics place it clearly in the Svelte ecosystem, listing svelte, svelte-5, sveltekit, component-library, components, headless and headlessui. The primary language is TypeScript, and the license is MIT. The author is Hunter Johnston, and the README credits Pavel Stianko for the design of the documentation. The last push was on 2026-09-22, the same day the newest release went out, so the project is actively moving.
Documentation lives at bits-ui.com/docs, which is where the examples are. The README itself is short: badges, credits, sponsors and a license statement.
The credits list explains the architecture
Four projects are credited in the README, and each one tells you something about the design.
Melt UI is credited as a powerful builder API that inspired the internal architecture of Bits UI. That is the most informative line, because Melt UI is a builder API rather than a component set, which is exactly the shape Bits UI ended up with. Radix UI is credited as the headless component APIs the project took heavy inspiration from, and React Spectrum is credited as a collection of headless components it also drew on. Bitworks is credited as the design team behind the documentation and example components.
So the lineage runs from two mature headless libraries in React land into a builder API in Svelte, and then into primitives. What you inherit from that lineage is a bias toward small composable pieces with well-defined state, and a bias toward accessibility being a solved problem rather than a feature request.
It also means the API shape will look familiar if you have used Radix. If you have used Melt UI, you will recognise the state model. Neither is a substitute for reading the docs, but both shorten the distance.
Reading the patch notes to understand the hard parts
The release history is the most informative document in the repository, because it names the problems a headless component layer actually has. Three consecutive patch releases in September 2026 give a clear picture.
Version 2.19.1, published on 2026-09-08, fixed Avatar detaching image handlers on destroy and actually applying the load cleanup, corrected Menu roles so GroupHeading no longer sets role group and Separator sets role separator, guarded a deferred focus handler against teardown in DismissibleLayer, and applied DateField segments in year, month and day order so a valid day is not clamped by the placeholder's month in day-first locales. That last one is a genuinely subtle internationalization bug that most libraries ship for years.
Version 2.19.2, on 2026-09-09, rendered the id attribute on Popper-based content elements so aria-describedby on triggers resolves correctly, restored body styles when delayed scroll-lock cleanup runs after the document is replaced, and respected an explicit Tabs.Content tabindex.
Version 2.19.3, on 2026-09-22, prevented delayed focus-scope autofocus from overriding focus already established elsewhere in the scope, stopped a rest prop from landing on the content element as a lowercase attribute, ignored Floating autoUpdate callbacks that fire after the effect is destroyed, and fixed user-select none being stranded on body after clicking inside forceMounted content, which had left whole pages unselectable until a reload.
That last fix, across Popover, Tooltip, Dialog, AlertDialog, Menu and Select, is the kind of bug you only discover by shipping. The pattern across all three releases is focus, roles and cleanup on teardown, which tells you where the complexity lives.
A pnpm monorepo with Playwright coverage
The repository is a pnpm workspace rather than a single package. The root package.json is named root with version 0.0.0 and a description of Monorepo for bits-ui, and the real work lives under packages/ alongside docs/, tests/ and a bundle-analyzer/ directory. Lock and workspace configuration come from pnpm-lock.yaml and pnpm-workspace.yaml, and the engines field requires pnpm 10.12.1 or newer, which is worth checking before you start if you have an older pnpm on your machine.
There is a single test entry point, plus narrower ones:
pnpm testThat expands to a filtered run across the packages and tests workspaces. Browser tests are separate and run through Playwright, which the root package.json takes as a catalog dependency, and there are dedicated scripts for components, for the library's own utilities, and for a chromium-only run. Linting runs both oxlint and eslint together, so a rule can live in either without the other duplicating it. Prettier is present with plugins for Svelte and Tailwind, and formatting is a single command at the root.
Bundle size gets tooling of its own. The bundle-analyzer package provides both an analyze script and a compare script, which is how you find out whether a new import pulled something heavy in. There is also a changeset workflow, with @changesets/cli in the dev dependencies and a ci:publish script that builds the packages and then runs changeset publish. That is what produces the patch, minor and major version numbers you see on npm.
What the documentation has to carry
Here is the honest limitation of this project. Because the components are unstyled, the documentation is not a nice-to-have, it is most of the usable surface area. The README is a page with badges, a hero image, four credits, a sponsors list, a license statement and a Discord link. Everything that tells you how to actually use the library is on bits-ui.com/docs.
That is a legitimate choice for a headless library, since the examples have to show your markup rather than the library's. It does mean the repository itself will not tell you which components exist. The release notes are the best substitute, because they name them as they come up: Dialog, AlertDialog, Popover, Tooltip, Menu, Select, Combobox, DropdownMenu, ContextMenu, Menubar, LinkPreview, Avatar, Tabs, DateField, and the DismissibleLayer and Floating layer primitives they share.
If you are evaluating whether a component you need exists, the release history is a reasonable index and the docs site is the answer. If you are trying to understand the API before installing, you will find less in the repository than you might expect.
The Svelte Discord community linked from the README is where questions go, and for a project built on community contributions that is worth having open in a tab while you work.
Where the design lineage and the real trade sit
The README credits two projects outside the Svelte world, and both are useful reference points. Radix UI is described as the headless component APIs the project took heavy inspiration from, and React Spectrum as a collection of headless components it also drew on. If you have shipped accessible overlays in another framework, the component set will feel recognisable, and the accumulated behaviour behind them is the real comparison rather than the API surface.
Melt UI is the closer comparison. The README credits it as a powerful builder API that inspired the internal architecture of Bits UI, so the two belong to the same family and choosing between them comes down to API preference and project maturity rather than a different level of capability.
The real trade is between a maintained dependency and code you own. Because Bits UI ships as a package, you get the fixes described above without writing them, including the body style cleanup and the DateField ordering bug, at the cost of accepting whatever the maintainers decide in a patch release. A styled component library asks for less from you but decides your markup for you. Neither answer is wrong, but they are different amounts of control.
Editorial conclusion
Bits UI is the right choice when you want accessible component behaviour without adopting someone else's design system, particularly if you are on Svelte 5 and comfortable composing parts yourself rather than importing a finished dropdown. It is a poor fit if you want a battery-included theme, because nothing is styled and the documentation site is where the examples live, and the README itself is a page of credits and badges. Install `bits-ui` alongside Svelte 5, read the docs for the component you need at bits-ui.com/docs, and read the release notes before upgrading, since the recent patches are fixes to focus scope, aria-describedby resolution and body style cleanup in exactly the edge cases a headless layer has to get right.
Frequently asked questions
What is Bits UI and what does headless mean here?
Bits UI is an MIT-licensed library of headless components for Svelte 5. Headless means the components ship behaviour, state and accessibility attributes with no styling attached, so you render the parts inside your own markup and own every visual decision.
How do I install Bits UI in a Svelte project?
The package is published to npm as bits-ui and the repository is a pnpm workspace requiring pnpm 10.12.1 or newer for working on it directly. The README points to bits-ui.com/docs for the full setup and usage documentation rather than giving install steps itself.
How does Bits UI compare to Melt UI and shadcn-svelte?
The README credits Melt UI as the builder API that inspired the internal architecture, so the two are close cousins differing mostly in API preference. Radix UI and React Spectrum are the headless libraries it took inspiration from, which is a different kind of comparison: same philosophy, different framework.
Does Bits UI work with Svelte 5?
Yes. The repository topics list svelte, svelte-5 and svelte5, and the project is built in TypeScript with a pnpm workspace. Recent patch releases fix focus scope, ARIA id resolution and body style cleanup across components such as Dialog, Menu, Select and Avatar.
Is Bits UI actively maintained?
Yes. The last push was on 2026-09-22 and the repository is not archived, with version 2.19.3 published the same day. Releases ship through changesets, and the root package.json has a ci:publish script that builds the packages and publishes the changeset.
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/huntabyte-bits-ui)