- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Collapsible
- Combobox
- Command
- Context Menu
- Data Table
- Date Picker
- Dialog
- Direction
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input OTP
- Item
- Kbd
- Label
- Menubar
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Resizable
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
- Typography
The shadcn CLI supports package imports
for installing components, rewriting imports, and resolving third-party
registries.
Package imports let you use private #... import aliases from your
package.json instead of compilerOptions.paths in tsconfig.json.
Example
You configure imports in your package.json:
{
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
}
}Then import generated components using #... specifiers:
import { Button } from "#components/ui/button"
import { cn } from "#lib/utils"Package import specifiers must start with #. Use TypeScript 5 or later with
moduleResolution: "bundler" and resolvePackageJsonImports: true.
App
For Next.js, Vite, and TanStack Start apps that install components into the same workspace.
Configure package.json
Add imports for the shadcn/ui install targets.
{
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
}
}If your app does not use a src directory, remove src/ from the targets. For
example:
{
"imports": {
"#components/*": "./components/*.tsx",
"#lib/*": "./lib/*.ts",
"#hooks/*": "./hooks/*.ts"
}
}Configure TypeScript
Enable package import resolution.
{
"compilerOptions": {
"moduleResolution": "bundler",
"resolvePackageJsonImports": true
}
}You do not need compilerOptions.paths for these aliases.
Configure components.json
Use the same #... roots in components.json.
{
"aliases": {
"components": "#components",
"ui": "#components/ui",
"lib": "#lib",
"hooks": "#hooks",
"utils": "#lib/utils"
}
}The ui alias uses #components/ui. It is still covered by the
#components/* import in package.json.
The utils alias uses #lib/utils. It is covered by #lib/*, so you do not
need a separate #utils import.
Monorepo
In a monorepo, use package imports for files inside each package and package exports for files shared across workspaces.
For an app workspace:
{
"name": "web",
"private": true,
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
},
"dependencies": {
"@workspace/ui": "workspace:*"
}
}{
"aliases": {
"components": "#components",
"ui": "@workspace/ui/components",
"lib": "#lib",
"hooks": "#hooks",
"utils": "@workspace/ui/lib/utils"
}
}For the shared UI package:
{
"name": "@workspace/ui",
"private": true,
"imports": {
"#components/*": "./src/components/*.tsx",
"#lib/*": "./src/lib/*.ts",
"#hooks/*": "./src/hooks/*.ts"
},
"exports": {
"./globals.css": "./src/styles/globals.css",
"./components/*": "./src/components/*.tsx",
"./lib/*": "./src/lib/*.ts",
"./hooks/*": "./src/hooks/*.ts"
}
}{
"aliases": {
"components": "#components",
"ui": "#components",
"lib": "#lib",
"hooks": "#hooks",
"utils": "#lib/utils"
}
}When you run add from apps/web, app-local files use #... imports and
shared UI files are imported from @workspace/ui.
import { Button } from "@workspace/ui/components/button"
import { LoginForm } from "#components/login-form"File extensions
The target pattern in package.json#imports controls whether generated imports
include file extensions.
{
"imports": {
"#components/*": "./src/components/*.tsx"
}
}This generates imports without extensions:
import { Button } from "#components/ui/button"If you use a target without the extension:
{
"imports": {
"#components/*": "./src/components/*"
}
}The generated import keeps the source extension:
import { Button } from "#components/ui/button.tsx"For most apps, use the extension in the target pattern.
Troubleshooting
If TypeScript cannot resolve a #... import, check that:
- the specifier starts with
# - the
importsentry is in the nearestpackage.json moduleResolutionis set tobundlerresolvePackageJsonImportsis enabled- the matching target exists after components are added
If a component is installed but imports still point to @/..., check that
components.json uses the same #... aliases as your package imports.