Prerequisites
Problem or motivation
Every item in the published registry has a placeholder description. public/r/registry.json contains 158 items sharing four distinct description strings, because build-registry-index.ts falls back to a generic label when a component declares none:
const description = item.description || `A ${item.type.replace('registry:', '')} component.`
So pixel-trail is published as "A ui component.", and so is everything else.
This matters more than it used to. The shadcn CLI's registry search is fuzzy and ranks across titles and descriptions, so descriptions are what let someone find a component they cannot already name. With placeholders, fancy is only reachable by exact name:
$ shadcn search @fancy -q "text that follows the cursor"
(nothing useful)
$ shadcn search @fancy -q "pixel trail"
- @fancy/pixel-trail (ui) - A ui component.
That is a real discoverability cost for a library whose components are mostly visual effects, where the name is often the hardest thing to guess. Agent-driven workflows feel it most, since an assistant asked for "letters that scatter on hover" has nothing to match against.
There is currently nowhere to put a description even if you wanted one. registrySchema in src/fancy/schema.ts has no description field, so the build has nothing to read.
Proposed solution
Let a component declare a description in the sidecar .json that already sits next to it, the same file that carries cssVars and additionalDependencies today:
{
"description": "Divides the container into a pixel grid that lights up and fades out as the cursor passes over it, leaving a trailing wake of squares."
}
Two small changes make that flow through:
- Add
description: z.string().optional() to registrySchema.
- Add
...(additionalConfig?.description && { description: additionalConfig.description }) in generateRegistryItem, following the existing tailwind and cssVars pattern.
The existing fallback stays, so anything without a description is unaffected.
I have this working locally, along with a description for all 45 components under src/fancy/components, written by reading each component's source and its demo. After rebuilding, descriptive search works:
$ shadcn search @fancy -q "text that follows the cursor"
- @fancy/text-along-path (ui) - Renders text following a custom SVG path, animating its position along the...
- @fancy/variable-font-cursor-proximity (ui) - Interpolates each letter's variable font axes individually based on...
$ shadcn search @fancy -q "physics simulation with draggable elements"
- @fancy/cursor-attractor-and-gravity (ui) - Runs a Matter.js physics simulation where draggable DOM elements are...
Happy to open a PR with it. Two things I would rather you decide than guess at:
- The sidecar
.json is the least invasive home, since the loader already reads it, but a JSDoc comment in the .tsx would keep the text next to the code. I went with the sidecar.
- I only described the 45 components, not the 99 demos, which keep the placeholder. Demos could inherit from their parent component, but that is a separate change and I did not want to bundle it.
Alternatives considered
Deriving a description from the component name, which is what the current fallback effectively does and is the thing causing the problem. Generating them from source at build time, which would be unpredictable and would put text nobody reviewed in front of users.
Prerequisites
Problem or motivation
Every item in the published registry has a placeholder description.
public/r/registry.jsoncontains 158 items sharing four distinct description strings, becausebuild-registry-index.tsfalls back to a generic label when a component declares none:So
pixel-trailis published as "A ui component.", and so is everything else.This matters more than it used to. The shadcn CLI's registry search is fuzzy and ranks across titles and descriptions, so descriptions are what let someone find a component they cannot already name. With placeholders,
fancyis only reachable by exact name:That is a real discoverability cost for a library whose components are mostly visual effects, where the name is often the hardest thing to guess. Agent-driven workflows feel it most, since an assistant asked for "letters that scatter on hover" has nothing to match against.
There is currently nowhere to put a description even if you wanted one.
registrySchemainsrc/fancy/schema.tshas nodescriptionfield, so the build has nothing to read.Proposed solution
Let a component declare a description in the sidecar
.jsonthat already sits next to it, the same file that carriescssVarsandadditionalDependenciestoday:{ "description": "Divides the container into a pixel grid that lights up and fades out as the cursor passes over it, leaving a trailing wake of squares." }Two small changes make that flow through:
description: z.string().optional()toregistrySchema....(additionalConfig?.description && { description: additionalConfig.description })ingenerateRegistryItem, following the existingtailwindandcssVarspattern.The existing fallback stays, so anything without a description is unaffected.
I have this working locally, along with a description for all 45 components under
src/fancy/components, written by reading each component's source and its demo. After rebuilding, descriptive search works:Happy to open a PR with it. Two things I would rather you decide than guess at:
.jsonis the least invasive home, since the loader already reads it, but a JSDoc comment in the.tsxwould keep the text next to the code. I went with the sidecar.Alternatives considered
Deriving a description from the component name, which is what the current fallback effectively does and is the thing causing the problem. Generating them from source at build time, which would be unpredictable and would put text nobody reviewed in front of users.