23rd is an open-source shadcn/ui registry of tasteful, opinionated UI components. Copy what you need, paste into your app, and ship, without fighting a kitchen-sink design system.
Site: 23rd.dev · Docs: 23rd.dev/docs
Why 23rd
Most kits hand you every option. 23rd picks a direction: spacing, motion, and interaction patterns that already feel finished. You can still override anything; you just start from a sharper baseline.
- shadcn-native: install with the CLI, own the source in your repo
- Opinionated defaults: less boilerplate, clearer decisions
- React and Svelte 5: every published registry item ships for both; pick a framework on the install command
Quick start
Install a component (React):
pnpm dlx shadcn@latest add @23rd/gooey-color-picker
Svelte 5 (lands in src/lib/components/ui/):
pnpm dlx shadcn@latest add @23rd/gooey-color-picker-svelte
Or pull straight from GitHub:
pnpm dlx shadcn@latest add radiumcoders/23rd.dev/gooey-color-picker
Agent skill - IN BETA STAGE
The 23rd agent skill teaches a coding agent every published registry component: which one fits, how to install it for React or Svelte, and the props that actually exist. It also knows when not to use a component.
npx skills add radiumcoders/23rd.dev --skill 23rd
Global install:
npx skills add radiumcoders/23rd.dev --skill 23rd -g
skills/23rd/ is the copy the skills CLI discovers. .cursor/skills/23rd/ is the same skill for Cursor /23rd in this repo. Docs: 23rd.dev/docs.
Components
| Component | Install | Description |
| ------------------------------------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------- |
| ASCII Fluid | @23rd/ascii-fluid | Mouse-trail WebGL fluid quantized to a clean ASCII brightness ramp |
| ASCII Logo | @23rd/ascii-logo | Interactive ASCII wordmark: hover shove, then click to scatter, drop, and gather |
| Dithered 404 | @23rd/dithered-404 | Bayer-pixel 404; a fireball cursor scorches it into embers and smoke, then it reforms |
| Folio | @23rd/folio | The page leans back in perspective while you scroll, blurs, then springs flat |
| Gooey Color Picker | @23rd/gooey-color-picker | Floating swatch → hue wheel, alpha, hex, joined by an SVG gooey filter |
| Live Orb | @23rd/live-orb | An evenly lit sphere with two capsule eyes that follow the pointer |
| Logo Burst | @23rd/logo-burst | Hair-line tentacles explode from the center, then breathe, light and dark |
| Phosphor Score | @23rd/phosphor-score | Vertical CRT sheet music; notes fall, bloom at the playhead, then exit in a flare |
| Radiant Lines | @23rd/radiant-lines | Hyperspace starfield background; warp speed driven by scroll |
| Shader Anime Fire | @23rd/shader-anime-fire | Cel-shaded flames licking up from the bottom of a landing hero |
| Shader Gradient | @23rd/shader-gradient | Quiet WebGL wash behind landing heroes, empty states, and marketing sections |
| Shader Sky | @23rd/shader-sky | Clear blue or rain behind a hero; drifting clouds, optional window-glass film |
| Shader Metal | @23rd/shader-metal | Liquid chrome, gold, or copper ribbons; the key light follows the pointer |
| Stretchy Footer | @23rd/stretchy-footer | Dia-style rubber overscroll; aurora stretches past the bottom, then snaps back |
| Typewriter | @23rd/typewriter | A playable typewriter in SVG; keys press, typebars strike, the carriage steps |
import { GooeyColorPicker } from "@/components/ui/gooey-color-picker"
export function Example() {
return (
<GooeyColorPicker
defaultValue={{ h: 210, s: 90, l: 55, a: 1 }}
onChange={(color, css) => console.log(color, css)}
/>
)
}
Svelte:
<script>
import GooeyColorPicker from "$lib/components/ui/gooey-color-picker.svelte"
</script>
<GooeyColorPicker
defaultValue={{ h: 210, s: 90, l: 55, a: 1 }}
onChange={(color, css) => console.log(color, css)}
/>
Develop locally
This repo is the docs site and registry source.
pnpm install
pnpm dev
Useful scripts:
| Script | What it does |
| --------------------- | ------------------------------------------------------ |
| pnpm dev | Next.js dev server |
| pnpm build | Build registry, OG cards, and the production app |
| pnpm preview | Build with OpenNext and preview in the Workers runtime |
| pnpm cf:deploy | Build with OpenNext and deploy to Cloudflare Workers |
| pnpm cf:upload | Build with OpenNext and upload a preview version |
| pnpm registry:build | Emit public/r/*.json from registry/ |
| pnpm test | Registry, Svelte compile, OG, and sponsors tests |
| pnpm typecheck | MDX + TypeScript check |
| pnpm lint | ESLint |
Stack: Next.js 16, React 19, Fumadocs, Tailwind CSS 4, shadcn/ui (Base UI), Cloudflare Workers (OpenNext).
Deploy to Cloudflare
pnpm cf:deploy
GitHub Actions deploys production on push to main. Opening a PR uploads a preview version (production is untouched) and comments a stable URL, the same idea as Vercel preview deployments:
https://pr-
That alias stays put as you push more commits to the same PR. Preview URLs live on workers.dev; they are public unless you later put Cloudflare Access in front of them.
You can get the same PR comments from Workers Builds instead: connect the repo in the Cloudflare dashboard, set the deploy command to pnpm cf:deploy, the non-production command to pnpm cf:upload, and enable Builds for non-production branches. Don’t run both Workers Builds and this GitHub Action for the same events or you’ll double-deploy.
Point 23rd.dev DNS at the Worker when you’re ready to cut over from Vercel.
Sponsors (Creem)
The sponsors page is the same empty-slot board as shadscan: Diamond $250/mo, Platinum $100/mo, Gold $50/mo, Silver $20/mo. Live Creem payment links are wired, so empty slots open checkout.
1. Create the Creem store
- Sign up at creem.io and open the dashboard.
- Leave Test Mode on (sidebar toggle) while you wire this up. Test and live products/keys are completely separate.
- Complete store details if the dashboard asks for them. Live payouts later need KYC/KYB under Balances → Payout Account.
2. Create the four subscription products
In Products, create one recurring / every-month / USD product per tier:
| Product name | Price | Env var |
| ------------- | ----- | ------------------------------------- |
| 23rd Diamond | $250 | CREEM_SPONSOR_DIAMOND_CHECKOUT_URL |
| 23rd Platinum | $100 | CREEM_SPONSOR_PLATINUM_CHECKOUT_URL |
| 23rd Gold | $50 | CREEM_SPONSOR_GOLD_CHECKOUT_URL |
| 23rd Silver | $20 | CREEM_SPONSOR_SILVER_CHECKOUT_URL |
On each product, set the success URL to https://23rd.dev/sponsors/thanks (or http://localhost:3000/sponsors/thanks in test). Click Share and copy the payment link (https://www.creem.io/payment/prod_...).
You can do the same from the Creem CLI after creem login --api-key creem_test_...:
creem products create \
--name "23rd Diamond" \
--description "Monthly Diamond sponsorship: logo, link, and release notes." \
--price 25000 \
--currency USD \
--billing-type recurring \
--billing-period every-month \
--tax-category saas
Prices are in cents (25000 = $250.00). Repeat for 10000, 5000, and 2000.
3. Put the links in env
Live payment links are already in wrangler.jsonc, .env.example, .dev.vars.example, and the fallback in lib/sponsors.ts.
Local Next.js (pnpm dev): copy .env.example → .env.local.
Local OpenNext/Wrangler (pnpm preview): copy .dev.vars.example → .dev.vars.
A Cloudflare Worker secret with the same name overrides the wrangler.jsonc var:
npx wrangler secret put CREEM_SPONSOR_DIAMOND_CHECKOUT_URL
npx wrangler secret put CREEM_SPONSOR_PLATINUM_CHECKOUT_URL
npx wrangler secret put CREEM_SPONSOR_GOLD_CHECKOUT_URL
npx wrangler secret put CREEM_SPONSOR_SILVER_CHECKOUT_URL
Paste the matching https:// payment link when prompted. Redeploy after changing a secret.
Contributing
New components live under registry/ with a vanilla engine, React/Svelte wrappers, and a registry.json (React item plus ), then get documented in content/docs/components/. Run pnpm registry:build before shipping registry changes.
PRs that sharpen defaults, fix edge cases, or add tasteful components are welcome.
Links
Made by radiumcoders (Jay).