0 dependencies · 25 components · 25 blocks · 6 palettes

Components you own, not components you install.

Every PresetUI component is one JavaScript file that imports nothing but React. You copy it in and it stops being ours. There is no package to update and nothing to override.

Change a token. Everything follows.

try a theme →

surface
#ffffff
fg
#0a0a0a
muted
#737373
border
#e5e5e5
accent
#0a0a0a
accent-fg
#ffffff
danger
#dc2626

optional

success
#16a34a
warning
#d97706
NewDraft

Invite a teammate

They'll get access to every project in this workspace.

Nothing above was restyled. Each theme rewrites the same custom properties, and every component reads only those — which is why rebranding the kit is a stylesheet edit, not a refactor. All 6 palettes.

Blocks, not just parts

all 25 blocks →

Whole sections assembled from the components — headers, heroes, features, pricing, FAQs, auth screens, an app shell. A starting point you rewrite, rather than something you configure.

Three steps, then you're on your own

  1. 01

    Paste seven CSS variables

    One @theme block in your global stylesheet. This is the only code PresetUI components share.

  2. 02

    Copy one file

    Open a component, switch to the Source tab, paste it into components/ui/. It imports nothing but React, so nothing else comes with it.

  3. 03

    Change whatever you want

    It's an ordinary file in your repo now. Rename it, delete a variant, rewrite the markup. Nothing upstream can disagree.

25 components so far

see them all on one page →

Each page has three tabs: the live component, how you'd use it, and the file you copy.

Accordionaccordion.js

Collapsible sections built on native details elements.

Alertalert.js

Short message set apart from the surrounding text.

Avataravatar.js

Circular user image with a text fallback behind it.

Badgebadge.js

Compact label for status and metadata.

Breadcrumbbreadcrumb.js

Trail of links back up the hierarchy.

Buttonbutton.js

Clickable action element with four variants and three sizes.

Cardcard.js

Composable surface with header, content, and footer slots.

Checkboxcheckbox.js

Native checkbox with the box painted over.

Dialogdialog.js

Modal built on the native dialog element.

Inputinput.js

Single-line text field with an invalid state.

Kbdkbd.js

A keyboard key, for shortcuts written into prose.

Labellabel.js

Form label with an optional required marker.

Paginationpagination.js

Page navigation that collapses the middle to an ellipsis.

Progressprogress.js

Determinate progress bar in three sizes.

Radioradio.js

Native radio with the dot painted over.

Selectselect.js

Native dropdown with the platform arrow replaced.

Separatorseparator.js

Dividing line, horizontal or vertical.

Skeletonskeleton.js

Placeholder block for content that hasn't arrived.

Sliderslider.js

Native range input with the track and thumb restyled.

Spinnerspinner.js

Indeterminate loading indicator in three sizes.

Switchswitch.js

On/off control built on a hidden checkbox.

Tabletable.js

Data table composed from the real table elements.

Tabstabs.js

Tabbed panels with arrow-key navigation.

Textareatextarea.js

Multi-line text field with an invalid state.

Tooltiptooltip.js

Hover and focus label, positioned with CSS alone.

Built to be readable by an agent

The whole kit — theme and every component — is served as one plain text document. An agent fetches it once and writes the files. No registry format to parse, no CLI to install.

/llms.txtopen →
# PresetUI — zero-dependency
# React + Tailwind components
#
# Do not install these from npm.
# There is no package.

## Setup — @theme block
## Accordion— /r/accordion.txt
## Alert   — /r/alert.txt
## Avatar  — /r/avatar.txt
## Badge   — /r/badge.txt
## …and 21 more
say this to your agent

Read https://presetui.com/llms.txt and write the components into components/ui/ as .js files. Do not install any packages.

Against installing a package

Copying has real costs. Here they are next to the benefits.

PresetUIA component package
To start using itCopy a filenpm install
Where the code livesYour reponode_modules
Changing a variantEdit the fileOverride, fork, or file an issue
Breaking changesNone — nothing updatesWhenever you upgrade
What you shipThe lines you keptThe whole package
Class conflictsResolved by stylesheet orderResolved by tailwind-merge

The last row is the one that bites. Without tailwind-merge, a className that collides with one the component already sets is decided by stylesheet order, not by you. It's the price of the file carrying no dependencies.