Shadcn Registry: A Better Way to Manage Your UI Components
Introduction
The shadcn registry enables you to create and manage custom component registries, making it easier to distribute components, hooks, pages, and other files across multiple React projects.
This blog post won’t be a step-by-step guide on setting up the registry, there’s already a solid one by the goat 🐐 himself. Instead, consider this a complementary resource, diving into some lesser-known CLI options and insights I picked up while setting it up.
Bird’s-eye view of the shadcn registry
The shadcn registry allows you to manage and distribute reusable UI components across multiple projects without relying on a traditional npm package. Instead, you use the shadcn
CLI to pull components directly into your codebase, giving you full control over customization and updates.
When setting up a registry, you define a structured collection of components, hooks, and other files that can be installed into different projects. The CLI handles fetching these components and placing them in the correct directories. Unlike manually copying components between projects, the registry offers a more efficient way to maintain consistency while allowing flexibility for customization, making it especially useful for teams or individuals working across multiple projects.
General notes on shadcn registry
registry-item.json
The
registry-item.json
schema is used to define your custom registry items.You can see the JSON Schema for
registry-item.json
here.registryDependencies: As mentioned in this documentation section, you can specify dependencies for your component, page, or hook. If it’s a shadcn/ui registry item, refer to it by name (e.g.,
button
,select
,input
). For items from other registries, use the full URL (e.g.,https://hookcn.ouassim.tech/r/use-boolean
).devDependencies: You can also specify development dependencies if needed.
files: You can list multiple files in the
files
property. This is useful for pages that may have multiple components, utilities, or hooks.{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "hello-world", "title": "Hello World", "type": "registry:block", "description": "A complex hello world component", "files": [ { "path": "registry/hello-world/page.tsx", "type": "registry:page", "target": "app/hello/page.tsx" }, { "path": "registry/hello-world/components/hello-world.tsx", "type": "registry:component" }, { "path": "registry/hello-world/components/formatted-message.tsx", "type": "registry:component" }, { "path": "registry/hello-world/hooks/use-hello.ts", "type": "registry:hook" }, { "path": "registry/hello-world/lib/format-date.ts", "type": "registry:utils" }, { "path": "registry/hello-world/hello.config.ts", "type": "registry:file", "target": "~/hello.config.ts" } ] }
tailwind.config.ts
If you’re placing registry components in a custom directory, update
tailwind.config.ts
to include that directory.export default { content: ["./registry/**/*.{js,ts,jsx,tsx}"] }
build command
Once you’ve added the build script to your
package.json
, runningbun run build
will, by default, search forregistry.json
, which contains the list of your registry items.If you want to specify a custom path instead of using the default
registry.json
, pass it as an argument:Terminal window
bun run build /registry/registry.json
Output files for each component are generated in
public/r
by default. To change the output directory, use the--output
option:Terminal window
bun run build --output /public/r/hooks
More details on the build command can be found in the shadcn build command docs.
Imports
Always use the @/registry path for imports:
import { HelloWorld } from "@/registry/hello-world/hello-world"
Publish your registry
- To make your registry available to other developers, you can publish it by deploying your project to a public URL.
next.config.ts
When serving your registry components, your URLs will likely follow this pattern:
https://[DOMAIN_NAME]/r/[NAME].json
Typically, you place registry item JSON files in the
public
directory, but instead of referencing full paths, you can simplify things using Next.js redirects. Here’s an example from my hookcn project:const nextConfig: NextConfig = { /* config options here */ async redirects() { return [ { source: "/r/:name((?!index\\.json|hooks/).*)", destination: "/r/hooks/:name.json", permanent: true, missing: [ { type: "query", key: "_redirected", value: undefined, }, ], }, ] }, }
This redirect ensures that any request starting with
/r/[NAME]
automatically points to its corresponding path inside the public directory.
Example repositories using the shadcn registry
Exploring real-world examples is the best way to see the shadcn registry in action. Here are some open-source projects that use it:
Conclusion
Although the shadcn registry is still an experimental feature, it’s definitely worth using if you need a shared component registry across multiple projects plus, shadcn is just awesome.
Peace ✌️.