resolveRegistryItems example return value
resolveRegistryItems returns a single merged object with: dependencies (array of strings), files (array of objects with path, type, content), cssVars (object with theme, light, dark keys containing CSS variable definitions), docs (string).
Registry error classes
All registry functions throw typed errors that extend `RegistryError`. Available error classes: RegistryError, RegistryNotFoundError, RegistryUnauthorizedError, RegistryForbiddenError, RegistryFetchError, RegistryNotConfiguredError, RegistryLocalFileError, RegistryParseError, RegistryValidationError, RegistryItemNotFoundError, RegistriesIndexParseError, RegistryMissingEnvironmentVariablesError, RegistryInvalidNamespaceError. Use `instanceof` checks to handle them.
loadRegistryItem function
Read a single item from a local `registry.json` by name using `loadRegistryItem(name, options)`. Options: cwd (defaults to process.cwd()). Returns a fully resolved registry item with file contents read from disk and inlined. Differs from `getRegistryItems` which resolves items from remote registry over the network.
loadRegistry function
Read and resolve a local `registry.json` file from disk using `loadRegistry(options)`. Options: cwd (defaults to process.cwd()), registryFile (defaults to "registry.json"). Follows any `include` references and returns the registry catalog. Omits file contents — like a built `registry.json` index. Differs from `getRegistry` which fetches remote registries over the network.
getRegistries function
Fetch the registry directory using `getRegistries(options)`. Accepts optional `useCache` parameter. Returns an array of registry entries, each containing name, url, and homepage fields.
addRegistryItems function
Resolve and install registry items into an existing project using `addRegistryItems(names, options)`. This is the programmatic equivalent of `shadcn add` and applies files, package dependencies, environment variables, CSS, and Tailwind configuration declared by the items. Accepts options: cwd, config, overwrite (default false), silent (default false). Does not read project configuration files itself — pass result of `getRegistriesConfig` or provide config directly. Throws errors instead of exiting and never prompts. Existing files are skipped unless overwrite is enabled.
resolveRegistryItems function
Resolve multiple items together with their registry dependencies using `resolveRegistryItems(names, options)`. Unlike `getRegistryItems`, this walks each item's `registryDependencies` and flattens everything — files, dependencies, CSS variables — into one single merged installable object containing dependencies, files, cssVars, and docs.
getRegistryItems function
Fetch one or more registry items by their qualified names using `getRegistryItems(names, options)` where names is an array of qualified names like `["@acme/button", "@acme/card"]`. Returns an array of registry items, each containing name, type, dependencies, and files array with path, type, and content.
getRegistry function
Fetch a single registry by name using `getRegistry(name, options)` where name is the registry namespace. Accepts optional `config` and `useCache` parameters.
getRegistriesConfig function
Load registry configuration from a project directory using `getRegistriesConfig(process.cwd())`. The function reads `components.json` when present; otherwise it reads the top-level `registries` field from `package.json`.
useCache option for registry functions
Registry functions accept an optional `useCache` boolean parameter (default: `true`). Registry responses are cached in memory for the lifetime of the process, keyed by resolved URL. Concurrent requests for the same URL are de-duplicated into a single fetch. Set to `false` in long-running processes (servers, watchers, MCP server) where the registry can change between requests and fresh data is needed each time.
config option for registry functions
Most registry API functions accept an optional `config` parameter of type `Partial<Config>` with default value of built-in registries only. The config's `registries` field maps a namespace (e.g. `@acme`) to a URL and any authentication headers or environment variables required to reach it.
CLI commands are not part of public API
The CLI commands themselves are not part of the public API. Only the imports documented in the API reference are considered stable.
searchRegistries function
Search across one or more registries with fuzzy matching using `searchRegistries(namespaces, options)`. Options include: query (string), types (array of registry types), limit (number), offset (number), config, continueOnError (boolean, default false). Returns pagination metadata object with total, offset, limit, hasMore, and items array containing name, title, type, description, registry, and addCommandArgument.
shadcn/schema import path
Zod schemas for validation are available under the subpath import `shadcn/schema`. Example: `import { registryItemSchema } from "shadcn/schema"`.
shadcn/registry import path
Registry functions are available under the subpath import `shadcn/registry`. Example: `import { getRegistryItems } from "shadcn/registry"`.
useMessageScrollerScrollable return values
useMessageScrollerScrollable returns which edges viewport can scroll toward for sibling UI needing values in JavaScript. Returns: start (boolean) - Whether viewport can scroll toward start, content hidden above, !start means at top; end (boolean) - Whether viewport can scroll toward end, content hidden below, !end means at bottom, stays false while follow-output keeps reader at live edge. Prefer data-scrollable attribute for styling scroller itself.
MessageScroller usage example with AI SDK
Complete MessageScroller example with custom styles and AI SDK integration:
```tsx
"use client"
import { useChat } from "@ai-sdk/react"
import { MessageScroller } from "@shadcn/react/message-scroller"
import { DefaultChatTransport } from "ai"
import { ChatInput } from "@/components/chat-input"
export function Chat() {
const { messages, sendMessage, status } = useChat({
transport: new DefaultChatTransport({ api: "/api/chat" }),
})
return (
<div className="flex h-svh w-full flex-col">
<MessageScroller.Provider>
<MessageScroller.Root className="relative flex flex-1 flex-col overflow-hidden">
<MessageScroller.Viewport className="flex flex-1 flex-col overflow-y-auto">
<MessageScroller.Content className="flex flex-col gap-4 p-6 text-base">
{messages.map((message, index) => (
<MessageScroller.Item
key={message.id}
messageId={`message-${index}`}
scrollAnchor={message.role === "user"}
>
<div className="rounded-lg bg-muted p-4">
{message.parts.map((part, i) =>
part.type === "text" ? (
<span key={i}>{part.text}</span>
) : null
)}
</div>
</MessageScroller.Item>
))}
</MessageScroller.Content>
</MessageScroller.Viewport>
<MessageScroller.Button className="absolute bottom-2 left-1/2 z-10 -translate-x-1/2 rounded-full border bg-background px-3 py-1 text-sm font-medium inert:opacity-0">
Jump to latest
</MessageScroller.Button>
</MessageScroller.Root>
</MessageScroller.Provider>
<ChatInput onSend={sendMessage} disabled={status !== "ready"} />
</div>
)
}
```
useMessageScrollerVisibility filtering
Filter visibleMessageIds from useMessageScrollerVisibility in your app when you need narrower outline, such as user messages, anchored turns, or search hits.
useMessageScrollerVisibility return values
useMessageScrollerVisibility provides visibility state for outline, search, and active-turn UI, subscribing separately from useMessageScrollerScrollable so visibility work only paid for when consumer needs it. Returns: currentAnchorId (string | null) - Current anchored turn based on last scrollAnchor item at or above reading line; visibleMessageIds (string[]) - Message ids intersecting viewport in document order.
useMessageScroller command options
useMessageScroller command options: align ("start" | "center" | "end" | "nearest", default "start") - How message target aligns in viewport; behavior (ScrollBehavior, default "auto") - Native scroll behavior for command; scrollMargin (number, default provider scrollMargin) - Margin applied to aligned edge for this command.
useMessageScroller methods
useMessageScroller provides imperative transcript controls: scrollToMessage(messageId: string, options?) - Scroll to a mounted message id, returns false when target not mounted and cannot be queued; scrollToEnd(options?) - Scroll to latest message, returns false only when viewport not mounted yet; scrollToStart(options?) - Scroll to top, returns false only when viewport not mounted yet.
MessageScroller.Button data attributes
MessageScroller.Button data attributes: data-direction ("start" | "end") - Mirrors direction; data-active ("true" | "false") - Whether this button can currently scroll.
MessageScroller.Button props reference
MessageScroller.Button props: behavior (ScrollBehavior, default "smooth") - Native scroll behavior used when button scrolls to target edge; direction ("start" | "end", default "end") - Transcript edge button scrolls toward; children (React.ReactNode) - Custom button content, defaults to scroll icon and accessible label; render (React.ReactElement | render function) - Custom render target; ...props (React.ComponentProps<"button">) - Props spread to button.
MessageScroller.Button purpose and behavior
MessageScroller.Button is a button that scrolls to the start or end of the transcript. It is inert and removed from tab order when there is nothing to scroll toward.
MessageScroller.Item data attributes
MessageScroller.Item data attributes: data-message-id (string) - Mirrors messageId when provided; data-scroll-anchor ("true" | "false") - Mirrors scrollAnchor.
MessageScroller.Item props reference
MessageScroller.Item props: messageId (string, required) - Stable row id used by scrollToMessage, visibility, and prepend preservation; scrollAnchor (boolean, default false) - Marks row as turn boundary that can anchor newly appended turns; ...props (React.ComponentProps<"div">) - Props spread to item element.
MessageScroller.Content props reference
MessageScroller.Content props: role (string, default "log") - ARIA role applied to message list for live announcements; aria-relevant (string, default "additions") - Live-region updates to announce, defaults to new transcript rows only; aria-busy (boolean) - Marks live region busy while turn streams, if needed; spacerClassName (string) - Class name for internal spacer used to make room for anchored rows; ...props (React.ComponentProps<"div">) - Props spread to content element.
MessageScroller.Viewport data attributes
MessageScroller.Viewport mirrors scroll-state data attributes: data-scrollable with value "start" | "end" | "start end" | absent (edges viewport can scroll toward, query with [data-scrollable~="end"], absent means it fits); data-autoscrolling present while viewport is programmatically scrolling to latest message.
MessageScroller.Viewport props reference
MessageScroller.Viewport props: preserveScrollOnPrepend (boolean, default true) - Keep first visible message item stable when older rows prepended; role (string, default "region") - Landmark role for labelled scrollable transcript viewport; aria-label (string, default "Messages") - Accessible name for scrollable chat transcript; tabIndex (number, default 0) - Makes transcript viewport keyboard-scrollable; ...props (React.ComponentProps<"div">) - Props spread to viewport element.
MessageScroller.Root frame and layout container
MessageScroller.Root is the frame and layout container that fills its parent, so it must be used inside a height-constrained layout within a MessageScroller.Provider. It accepts React.ComponentProps<"div"> spread to the frame element.
MessageScroller.Provider is headless root
MessageScroller.Provider is the headless root that owns scroll state and behavior props, providing them to parts and hooks. It renders no DOM of its own.
MessageScroller.Provider props reference
MessageScroller.Provider props: autoScroll (boolean, default false) - Follow new content only while reader is at live edge; defaultScrollPosition (string "start" | "end" | "last-anchor", default "end") - Opening position on first non-empty render, applied once, "last-anchor" opens at last scrollAnchor row and falls back to "end" when turn fits or no anchor exists; scrollEdgeThreshold (number, default 8) - Distance from either edge that counts as being at start or end, controls state attributes and scroll button visibility; scrollMargin (number, default 0) - Margin applied to aligned edge for scrollToMessage, visibility, and programmatic targets; scrollPreviousItemPeek (number, default 64) - Extra margin added to scrollMargin when newly appended scrollAnchor item is positioned so part of previous item stays visible.
MessageScroller.Content direct children requirement
Every direct child of MessageScroller.Content should be a MessageScroller.Item.
MessageScroller styled to unstyled parts mapping
Mapping from styled component parts to unstyled namespace parts: MessageScrollerProvider maps to MessageScroller.Provider, MessageScroller maps to MessageScroller.Root, MessageScrollerViewport maps to MessageScroller.Viewport, MessageScrollerContent maps to MessageScroller.Content, MessageScrollerItem maps to MessageScroller.Item, and MessageScrollerButton maps to MessageScroller.Button.
MessageScroller exports namespace object
The @shadcn/react package exports a namespace object instead of flat components. The parts and behavior are the same as the styled component, just unstyled.
message-scroller.tsx registry component
The message-scroller.tsx component in the registry is a thin wrapper that adds Tailwind classes on top of the headless primitive. Use the package directly when you want full control over markup and styles, or when not using the registry.
MessageScroller headless primitive in @shadcn/react
MessageScroller ships as a headless primitive in the @shadcn/react package. The package owns all scroll behavior including anchoring turns, following streamed output, preserving the reader's place as history loads, and tracking visibility. It renders no styles of its own.
Team-based access control for registries
Implement team-based access by extracting the token from the request, calling getTeamFromToken(token) to determine which team the user belongs to, then fetching components with getComponentsForTeam(team) and returning only the components that team can access.
Next.js API route for authenticated registry
Implement registry authentication in a Next.js API route at app/api/registry/[name]/route.ts. Extract tokens from the Authorization header using request.headers.get("authorization") and replacing "Bearer " prefix, or from query parameters using request.nextUrl.searchParams.get("token"). Return 401 status for invalid tokens and 403 for forbidden access. Call helper functions isValidToken(token) and hasAccessToComponent(token, name) to validate access.
Environment variable setup for registry tokens
Store sensitive registry authentication data in environment variables in a .env.local file, never in version control. Set variables like REGISTRY_TOKEN=your_secret_token_here and reference them in components.json using ${VARIABLE_NAME} syntax.
Query parameter authentication for registries
Query parameter authentication passes tokens as URL parameters. Configure it in components.json using the params object with key-value pairs like "token": "${ACCESS_TOKEN}". This appends parameters to the registry URL, e.g., https://registry.company.com/button.json?token=your_token.
API key authentication in registry headers
Some registries use API keys in custom headers. Configure multiple headers like X-API-Key and X-Workspace-Id in components.json under the registry's headers object, referencing environment variables like ${API_KEY} and ${WORKSPACE_ID}.
Token-based authentication in components.json
Token-based authentication uses Bearer tokens or API keys in the Authorization header. Configure it in components.json by specifying a registry URL and adding an Authorization header with a Bearer token. Reference environment variables like ${REGISTRY_TOKEN} in the header value.
Temporary token validation with expiration
Use temporary tokens for better security. A TemporaryToken interface has token (string), expiresAt (Date), and scope (string[]). Validation checks if the token exists in tokenData, then returns false if new Date() > tokenData.expiresAt, otherwise returns true.
Access logging for registries
Log registry access for security and analytics. Create records with timestamp (new Date()), userId, component name, ip (request.ip), and userAgent (request.headers["user-agent"]) to track who accessed which components.
Testing authenticated registries with curl
Test authenticated registries using curl with the Authorization header: curl -H "Authorization: Bearer your_token" https://registry.company.com/button.json
Testing authenticated registries with shadcn CLI
Test authenticated registries using the shadcn CLI by setting the REGISTRY_TOKEN environment variable: REGISTRY_TOKEN=your_token npx shadcn@latest add @private/button
HTTPS requirement for authenticated registries
Always use HTTPS URLs for registries with authentication to protect tokens in transit. HTTP registries are insecure and should never be used for authenticated endpoints.
Registry authentication error codes
The shadcn CLI handles three authentication error responses: 401 Unauthorized when token is invalid or missing, 403 Forbidden when token lacks permission for the resource, and 429 Too Many Requests when rate limit is exceeded.
Custom error messages from registry server
Registry servers can return custom error messages in the response body to provide context-specific guidance. Include an error field and a message field in the JSON response. The shadcn CLI displays the message to users, allowing you to guide them to solutions like subscription renewal or token requests.
Registry authentication use cases
Authentication enables keeping business logic and internal components secure (Private Components), giving different teams different components (Team-Specific Resources), limiting access to sensitive or experimental components (Access Control), tracking which components are used in the organization (Usage Analytics), and controlling access to premium or licensed components (Licensing).
Express.js registry server authentication example
Implement authentication in Express.js by extracting the Bearer token from req.headers.authorization with .replace("Bearer ", ""). Call isValidToken(token) to validate; return 401 status if invalid. Return 404 if component not found. Return the component as JSON if authorized.
Rate limiting for registry protection
Protect registries from abuse using rate limiting middleware. Example: express-rate-limit with windowMs: 15 * 60 * 1000 (15 minutes) and max: 100 (limit each IP to 100 requests per window). Apply to /registry routes with app.use("/registry", limiter).
User-personalized registry components
Personalize registry responses by authenticating the user from the request, retrieving their style and framework preferences with getUserPreferences(user.id), then fetching a personalized component version using getPersonalizedComponent(componentName, preferences).
Multiple registries with different authentication
In components.json, configure multiple namespaced registries with different authentication methods. Use the registries object with keys like @public, @internal, @premium. Each can have its own URL and headers or params. For example, @public can use a simple string URL, while @internal uses an Authorization Bearer token and @premium uses an X-License-Key header.
Token rotation strategy
Rotate access tokens regularly for security. Generate new tokens with crypto.randomBytes(32).toString("hex") and set expiration dates, typically 30 days from generation: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).
Dynamic search example response
Example registry.json response with pagination:
```json
{
"name": "acme",
"homepage": "https://acme.com",
"items": [
{
"name": "button",
"type": "registry:ui",
"description": "A button component."
},
{
"name": "icon-button",
"type": "registry:ui",
"description": "A button component with an icon."
}
],
"pagination": {
"total": 12,
"offset": 0,
"limit": 2,
"hasMore": true
}
}
```
Dynamic search pagination object properties
The pagination object has four properties: total (number, total number of items matching the query), offset (number, number of items skipped), limit (number, maximum number of items in this response), and hasMore (boolean, whether more items are available beyond this page).
Dynamic search response format
Return your regular registry.json shape with an additional pagination object. Search results only need name, type and description for each item. You do not need to include files, dependencies or other item properties. The CLI fetches the full item definition when the user runs shadcn add.