shadcn/ui is precise. Every component sits on the same grid, every radius matches, and a dashboard built from it looks like the other forty dashboards shipped that week. Looseleaf keeps the parts, the props and the data-slot names, then draws the surface as paper with ink lines on top. You install one component and your JSX does not change.
What Looseleaf actually does
Looseleaf is a React component library and a shadcn registry. The count is 123 components, which covers every shadcn part, including button, sidebar and chart, plus paper objects, marks, stickers, a sketchpad and a chat kit. On top of that sit 61 blocks: logins, signups, sidebars, dashboards, settings pages, pricing sections, chat, notes and landing blocks.
The art ships with the code. There are 160 icons, 48 doodles, 88 stickers, badges, stamps, and a mascot called Stubby drawn in 15 poses. Kevin Sans, the hand-lettered typeface, covers three roles: interface text, titles and stamps. All of it is generated by TypeScript, so nothing arrives as a folder of exported PNG files.
Because the parts and the props are the ones you already use, the swap does not touch your markup. Radix keeps the behaviour. Data attributes such as data-slot keep your existing selectors working.
Why hand-drawn stopped looking like a joke
Sketch interfaces used to be a costume. A doodle border around a form that still jumped on focus, still had a 16px tap target, still ignored the keyboard. The drawing promised warmth and the behaviour delivered nothing.
A drawn surface works when the drawing is the system rather than a skin on top of it. That is the difference between Looseleaf and a hand-drawn theme. The pen is a token, the stroke width is a token, the density is a token, and the components share one engine, so a button from one corner of the library and a chart from another look drawn by the same hand.
Treat the style as positioning rather than decoration. A notebook interface tells people the product is a place to think. That helps a journaling app, a course builder, a research tool or a small CRM. It fights a bank dashboard or a trading terminal with twelve columns of numbers. The look is a sentence you say about the product, and it only works where you want to say it.
How the ink engine draws a component
Everything you see drawn is one SVG element with a data-ink attribute, sitting behind the real DOM label. The label does the work: it holds the text, the focus ring and the click target. The SVG supplies the line.
The drawing itself is a pure TypeScript function in src/lib/ink/recipes/, one recipe per component. Each recipe takes a seed and returns an SVG path string, and the color comes from CSS variables rather than from the function. The same seed produces the same line on the server and in the browser, which is why the markup hydrates without a mismatch. Randomness is real, yet reproducible.
States are a CSS layer. Hover, press and focus reveal drawing that was generated ahead of time, so a pointer moving across a button does not call React at all. Every pen width, fill and density lives in a token with an --ll- prefix, aliased onto the semantic variables shadcn already defines.
☞ The consequence for a design system is practical. You retheme the drawn surfaces by editing tokens, the same way you retheme the flat ones. You are not editing SVG files by hand.
What ships in the registry
The registry splits into pieces, so you can install the minimum:
- ❶ The ink engine, holding seeded randomness, pens, shapes, fills, the grain and paper textures, the provider and the drawable layer
- ❷ The art kit, with the drawing DSL, the hand-lettering glyph font, rubber stamps and badges
- ❸ The paper theme, with tokens, keyframes and utilities merged into your global CSS
- ❹ The sketchpad, a real drawing surface where the pointer, a finger, pen pressure or the keyboard put strokes on paper, with undo, redo and SVG export
The blocks are worth a look even if you never use them. A login block arrives as a taped sheet on a desk, with the form checked by react-hook-form and zod, so the demo copy is also the production copy.
Installing one component without breaking your tokens
Add the registry to components.json once, under the key @looseleaf, pointing at https://kevintngo.github.io/looseleaf/r/{name}.json. Then pull the pieces you want:
npx shadcn@latest add @looseleaf/buttonnpx shadcn@latest add @looseleaf/login-01
The files land in your repo as source, inside components/ui and lib/ink. There is no new entry in dependencies, because there is no package to depend on. You own the code from the first minute, and you can edit a stroke without forking anything.
☛ One command needs care. npx shadcn@latest add @looseleaf/looseleaf installs everything, and its own description says it overwrites your global CSS tokens. On a fresh project that is a feature. On a product with an established theme, install single components instead and keep your palette.
Where it does not fit
Three limits are worth knowing before you plan a build around it.
There is no npm package. The repository is marked private at version 0.1.0, so the only route in is the shadcn registry, which assumes a project with components.json and the shadcn CLI. A plain create-react-app folder needs that setup first.
The stack is current. React 19 and Tailwind v4 are what the components are built and tested against. The theme relies on @theme mappings, which belong to Tailwind v4, so a v3 project needs the migration before the first install.
The visual language is loud. Drawn outlines compete for attention in a dense table, and a medical record or a finance dashboard loses reading speed when every cell is a small sketch. Use it where the drawing carries meaning, and keep the neutral set for the places where it does not.
How states and accessibility work
The library states its guarantees plainly. Keyboard navigation, a visible focus indicator, AA text contrast, 24px targets, reduced motion support, forced colors support, RTL layouts and three interface densities. Each one is a claim you can check in the demo with a keyboard and a high-contrast mode turned on.
The 24px target floor follows the WCAG target size criterion, which asks for at least 24 by 24 CSS pixels on pointer targets. Forced colors matters on Windows high contrast, where any interface that hardcodes colors turns into an unreadable block. A drawn surface fails that test faster than a flat one, so the support is not a detail.
Semantics stay with Radix. The drawing sits behind the real label, so the accessible name comes from the element a screen reader already understands. That is the reason a swapped button keeps working in a form without extra attributes.
Frequently asked questions
Can I drop it into an existing shadcn project?
Yes. Radix owns the behaviour in both libraries, so a replaced component keeps its imports and its props. Install single components and leave the full @looseleaf/looseleaf entry alone if you have a theme of your own, because that entry rewrites global CSS tokens.
Does it work with Tailwind v3?
Not out of the box. The components are built for Tailwind v4 and the theme uses @theme mappings with CSS variables. Plan the upgrade first, then install, otherwise the tokens have nothing to attach to.
Is it free for client work?
Yes. MIT covers the code, the art and Kevin Sans. IBM Plex Mono, used inside the code blocks, ships under the SIL Open Font License 1.1. Nothing asks for an account or a license key.
How do I install only a few components?
Add the registry entry to components.json, then name the piece you want, for example @looseleaf/button or @looseleaf/login-01. Each install writes its own files and pulls only the dependencies that piece needs.
Why it belongs in your stack
You want the shadcn workflow without the shadcn look. A registry solves that in a way a theme cannot, because the result is source you edit inside your own repo. An override file drifts away from upstream on every release, while this one moves only when you move it.
It pairs with the reading here. The guide to LiftKit for Figma and React covers the other end of the open source spectrum, where the design file and the components stay in sync. The piece on design to code with AI agents explains why a registry beats a package when a model writes the integration. If you are deciding whether a drawn look suits the product at all, read the state of retro and brutalist UI in 2026, which covers the taste question with examples.
To judge the motion and the states before installing, open the Looseleaf demo and run it with a keyboard. The source sits on GitHub, where the README carries the install steps and the recipe folder that generates the drawing.
When the screens you build need reference patterns, the other open source code and design and code kits cover the same ship-it-yourself workflow.

