21st-design-sync
Look at the current project's design (its shadcn / Tailwind CSS variables and color tokens) and publish it to the 21st.dev community as a shareable theme, using `21st publish-theme`. Use when the user says "publish my theme", "share our design as a 21st theme", "sync my design to 21st", "turn my glo
By 21st-dev · 823 installs
npx skills add 21st-dev/skill --skill 21st-design-sync
Source repository · Upstream listing
21st Design Sync — publish your project's design as a theme
Take the design a project already ships (its light + dark CSS variables) and
publish it to the public 21st.dev theme library so anyone can preview,
bookmark, and apply it. Under the hood this is one CLI call:
21st publish theme <file.css name "…" .
Pre flight (always)
1. Auth needs a real API key. publish theme is a management endpoint: it
accepts a 21st sk … key only , not a 21st login session token. Get one
at https://21st.dev/mcp (or https://21st.dev/settings/api keys ) and pass it via
api key 21st sk … or the TWENTYFIRST TOKEN / API KEY 21ST env var. If
the user has no key, point them there — don't try to mint one.
2. The CLI is the unified @21st dev/cli (bin 21st ). Use npx @21st dev/cli
if it isn't installed.
3. Publishing is public and outward facing. A published theme is immediately
is public in the community library (there is no unlisted/private option for
themes). Confirm with the user before publishing.
Step 1 — Find the project's design tokens
Locate the file that defines the shadcn/Tailwind theme variables. Check, in order:
app/globals.css , src/app/globals.css
src/index.css , styles/globals.css , app/styles/globals.css
You're looking for a :root { … } block of CSS custom properties
( background , foreground , card , primary , secondary ,
muted , accent , destructive , border , input , ring , the
chart / sidebar tokens, radius ) and a matching .dark { … }
block. Values may be hsl(...) , oklch(...) , hex, or raw channels — keep them
exactly as the project wrote them.
Tailwind v4 projects usually keep the same :root / .dark blocks plus an
@theme inline mapping; you only need the :root and .dark token values,
not the @theme mapping.
Step 2 — Assemble a valid theme CSS file
The publish endpoint parses name: value; pairs out of a :root { … } block
and a .dark { … } block, and requires both to be non empty . So the file
you publish must contain both.
Copy the project's :root and .dark blocks into a standalone file
(e.g. project theme.css ). Nothing else is required.
If the project has only a light :root and no .dark (or an empty one),
generate a dark variant before publishing — don't ship a theme with an empty
dark mode. Reuse the add dark mode / oklch skill approach: invert
lightness while preserving hue/chroma so the dark set stays on brand. Keep the
same token names.
Keep the token names shadcn standard so the theme previews correctly on the
card and applies cleanly for others.
Minimal shape:
Step 3 — Name & tag it
Name (required, ≤ 50 chars): infer from the project — the product/brand
name from package.json , the repo, or the site title. Ask the user if it's
ambiguous.
Tags (optional): a few descriptors that match how people browse themes,
e.g. dark , minimal , neutral , vibrant , saas . Pass comma separated.
Step 4 — Publish
The command prints the live theme URL ( https://21st.dev/community/themes/<slug ).
Share it with the user.
Updating vs re publishing
Each publish theme creates a NEW theme (there's no upsert by slug like
components have). Running it twice = two themes in the library.
To change name/tags/visibility on an existing theme, edit it in place:
21st edit <theme id type theme [ name "…"] [ tags a,b] .
To change the colors , publish a fresh file and remove the old one:
21st delete <theme id type theme yes (soft unpublish, reversible).
When NOT to use this
Syncing a component library to a Claude Design project → that's the
built in /design sync skill, a different destination.
Publishing a component (not a color theme) → use 21st registry .