
Shadcn Vue Skilld
- 22 installs
- 173 repo stars
- Updated May 5, 2026
- skilld-dev/vue-ecosystem-skills
Helps with ai & agent building tasks.
About
shadcn-vue-skilld is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- shadcn-vue-skilld
- AI & Agent Building
- AI-coding skill
Shadcn Vue Skilld by the numbers
- 22 all-time installs (skills.sh)
- +1 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #10,169 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/skilld-dev/vue-ecosystem-skills --skill shadcn-vue-skilldAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 22 |
|---|---|
| repo stars | ★ 173 |
| Last updated | May 5, 2026 |
| Repository | skilld-dev/vue-ecosystem-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Discussions Index
Q&A (20)
- #1457: Can't download the correct version of a component (+1) [answered] (2025-10-07)
- #1272: What is the recommended workflow for updating components after a new release? (+1) [answered] (2025-05-27)
- #1213: How to Change the Ring Color Variable in shadcn-vue? (+1) [answered] (2025-04-26)
- #1281: How to set a select options in Shadcn-vue AutoForm with Zod schema? (+1) [answered] (2025-05-30)
- #1238: I need some details about forms (+1) [answered] (2025-05-11)
- #1223: Has on example for select large options (+1) [answered] (2025-04-28)
- #1218: Tailwind 3 for new projects (+1) [answered] (2025-04-28)
- #1211: checkbox icon is not centered when checked (+1) [answered] (2025-04-26)
- #1118: How should I bind up NuxtLink with Button? (+1) [answered] (2025-03-21)
- #1586: Have tags input disappeared? (+1) [answered] (2025-11-22)
- #1236: Installed component differs from the one in source code (+1) [answered] (2025-05-09)
- #1210: how to adjust select components size? (+1) [answered] (2025-04-25)
- #1168: Disable auto-import in Nuxt (+1) (2025-04-09)
- #1566: Can't resolve 'tw-animate-css' (+2) (2025-11-18)
- #1535: Form or Field Component? (+5) (2025-11-11)
- #1460: Getting error when installing Sidebar component (+2) (2025-10-08)
- #1363: No import alias found in your tsconfig.json file. (+6) (2025-08-02)
- #1226: How to view old documentation ? (+2) (2025-05-01)
- #1647: Custom registry server (+1) (2026-01-05)
- #1498: Version update (+1) (2025-10-20)
How should I bind up NuxtLink with Button?
I think this is an issue with Nuxt but I don't know how should I achieve this. I have some buttons, and links to redirect users, but seems like the NuxtLink will have the styles and more like a real element, which will actually bring a Button with NuxtLink into two elements: The outter NuxtLink:
The inner Button:
<NuxtLinkLocale :to="item.link" class="rounded-full">
<Button
class="my-2 rounded-full font-semibold text-2xl px-12 py-6 justify-center items-center relative"
:disabled="item.disabled"
variant="ghost"
>
{{ t(item.name_key) }}
<Icon
v-if="item.isExternal"
icon="lucide:external-link"
class="w-6 h-6 absolute right-4 top-1/2 -translate-y-1/2"
/>
</Button>
</NuxtLinkLocale>---
Accepted Answer
This should be true that I finally still choose to keep the two nested components, the outside one is Nuxt Link, and the inner one is the button, which works fine but looks weird especially when for a11y or the tab select, where user can select two nested buttons.
>
Not to compare but Next.js should not have this issue, where I think they might render the Link component in a special way.
If you are wrapping a Button with NuxtLink you should use the custom prop on nuxtlink to prevent it from rendering an a tag around its contents.
Disable auto-import in Nuxt
Is there a way to disable auto-imports in the nuxt version of shadcn? I find that having Nuxt track all the components during development is really slowing the dev server down.
---
Top Comments
@sadeghbarati [maintainer]:
Don't use shadcn-nuxt module and also update nuxt.config
export default defineNuxtConfig({
imports: {
autoImport: false,
scan: false,
}
})@mathieumagalhaes:
You're looking for the components option in the nuxt.config file. This is a feature handled automatically by Nuxt and isn't related to shadcn-vue, or its nuxt plugin counterpart.
how to adjust select components size?
I would like to ask, how can I reduce the selection box, like the red one in the picture?
---
Accepted Answer
has data-size options:
<SelectTrigger data-size="sm"></SelectTrigger>checkbox icon is not centered when checked
I used the checkbox directly, but the icon was not centered.
---
Accepted Answer
.lucide {
width: 24px;
height: 24px;
stroke-width: 2px;
}It turned out that I modified the global icon.
How to Change the Ring Color Variable in shadcn-vue?
I'm working on an application and I want to customize the ring color used throughout my app.
How can I change the default focused ring color variable so that all components will be affected?
I do not want to go into every component and change it manually!
btw I use tailwindcss v3.4.1
---
Accepted Answer
I get it! To globally change the ring color, you can override the --ring variable in your main CSS file.
Here’s how I did it:
/* --ring: 0 0% 3.9%; */
--ring: 180 39% 52%;The value 180 39% 52% represents the following HSL (Hue, Saturation, Lightness) color model hsl(180, 39%, 52%)
Tailwind 3 for new projects
Is there a way to still use tailwind 3 for new projects?
---
Accepted Answer
Thank you for the replay!
The question should be how to start a new shadcn-vue project using tailwind 3. I was little confused since the shadcn-vue documentation states:
Note: this is non-breaking. Your existing apps with Tailwind v3 will still work. When you add new components, they'll still be in v3 until you upgrade. Only new projects start with Tailwind v4.
Solution
In other place in documentation I found this:
Note: The following guide is for Tailwind v4. If you are using Tailwind v3, use shadcn-vue@1.0.3.
I conclude, the tailwind 3 components can still be used by
e.g. npx shadcn-vue@1.0.3 add button
Thanks!
Has on example for select large options
I have 20,000 options and need to support drop-down and search. There are relevant sample codes?
---
Accepted Answer
Through AI, I made an example and successfully used it in my project. ...
How to view old documentation ?
I have a project that use shadcn vue prior to reka-ui, now all the documentation is pointing to the latest build, any way we can view the v1 of shadcn documentation ?
---
Top Comments
@sadeghbarati [maintainer] (+1):
For now, check this link
- https://radix.shadcn-vue.com/
- https://0252e16c.shadcn-vue.pages.dev/
@mcrio:
You can look up the source code of the documentation and search by tags. Example v0.11.4: https://github.com/unovue/shadcn-vue/tree/v0.11.4/apps/www/src/content/docs
Installed component differs from the one in source code
Hi. I'm trying to understand why a component installed via npm is different than what is in the source file on GitHub?
For example, installing the Command component using npx shadcn-vue@latest add command.
The classes are different, ie. the installed one has py-3 which is a lot, while the one from source has py-1.5.
style: New York
Installed:
<ListboxItem
v-if="isRender"
v-bind="forwarded"
:id="id"
ref="itemRef"
data-slot="command-item"
:class="cn(`data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-3 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`, props.class)"
@select="() => {
filterState.search = ''
}"
>
<slot />
</ListboxItem>---
Accepted Answer
Ok I just realized the default versions code is in the v4 folder.
I need some details about forms
I just started to use shadcn-vue, it I great but also a major shift from what I was used to with other libraries (primevue, quasar).
The major problem I have now is with forms.
<form> or <Form>?
The example for the Form component uses Form but the example for Checkbox uses form. I used form and it works but this is a bit weird when there is Form available.
value, handleChange, ...
Consider this code
<FormField
v-slot="{ value, handleChange }"
name="languageIds"
type="checkbox"
:unchecked-value="false"
v-for="lang in allLanguages"
:key="lang.id"
:value="lang.id"
>It works but where d...
---
Accepted Answer
As this is based on vee-validate you should check their docs as well. Regarding value and handleChange, it is something FormField provides using VueJs slots.
What is the recommended workflow for updating components after a new release?
Hi! I’m using shadcn-vue in my project and I add components using the CLI (not by manual copy/paste).
When a new release or bug fix comes out, what’s the recommended process for updating the components I’ve already installed via the CLI?
- Should I run the CLI again for each component I want to update?
- Will the CLI overwrite my local changes or customizations?
- What’s the safest workflow to keep everything up to date, especially if I’ve made some custom changes?
I’d appreciate any guidance or best practices for handling updates with the CLI.
Thanks!
---
Accepted Answer
@sadeghbarati [maintainer]:
First, set up Git in your project to enable access to the previous code history. This is important if you want to discard recent changes.
Keep in mind that using the CLI will overwrite your local changes. To avoid losing work, use shadcn-vue and the diff command to review differences and selectively apply updates.
You can use diff and copy the output into the AI chat to help apply the changes. Additionally, you can use #fetch in Copilot Chat to retrieve the latest registry updates for more accurate modifications.
How to set a select options in Shadcn-vue AutoForm with Zod schema?
I'm using ShadCN Vue with AutoForm and zod for schema validation. I'm trying to dynamically populate the select options for a field named accounts using an array of account objects.
My code: ...
---
Accepted Answer
Thanks to Navid Abedini and from the ShadCN Vue docs, I found it:
1. Single-Select “enum” Solution
Navid Abedini pointed out (and it works) that AutoForm’s default <select> support is tied to Zod’s z.enum(...). In other words, if your schema uses z.enum([...]) for that field, AutoForm will automatically render a <select> with those enum values:
...
No import alias found in your tsconfig.json file.
<img width="597" height="158" alt="image" src="https://github.com/user-attachments/assets/48f848d1-59ab-4630-8471-be5d61ca0b00" /> <img width="230" height="169" alt="image" src="https://github.com/user-attachments/assets/f2597d4f-e013-4f44-86da-97f28d570e2f" />
Can't download the correct version of a component
Hey,
When I run npx shadcn-vue@latest add sonner on my project, I get this component:
...
---
Accepted Answer
@sadeghbarati [maintainer]:
but if I want v4 I'd have this: "style": "new-york-v4"
No keep it as-is --> new-york
shadcn-vue CLI FALLBACK_STYLE is new-york-v4
function resolveStyleFromConfig(config: Partial<Config> | Config) {
if (!config.style) {
return FALLBACK_STYLE
}
// Check if we should use new-york-v4 for Tailwind v4.
// We assume that if tailwind.config is empty, we're using Tailwind v4.
if (config.style === "new-york" && config.tailwind?.config === "") {
return FALLBACK_STYLE
}
return config.style
}based on the code
- if there is no
styleincomponents.jsonfile, fallback tonew-york-v4
- if the style value is
new-yorkandtailwind['config']is empty, also fallback tonew-york-v4
- if style value is
new-yorkbuttailwind['config']is NOT empty picknew-yorkv3 registry
- if style value is
default, pick thedefaultv3 registry
---
Keep that in mind...
Getting error when installing Sidebar component
Hey everyone,
When I run npx shadcn-vue@latest add sidebar
I'm getting this error:
Something went wrong. Please check the error below for more details.
If the problem persists, please open an issue on GitHub.
[@vue/compiler-sfc] Failed to resolve import source ".".
ui/sidebar/Sidebar.vue
12 | })
13 |
14 | const props = withDefaults(defineProps<SidebarProps>(), {
| ^^^^^^^^^^^^
15 | side: "left",
16 | variant: "sidebar",This is what my components.json looks like:
{
"$schema": "https://shadcn-vue.com/schema.json",
"style": "new-york",
"typescript": false,
"tailwind": {
"config": "",
"css": "src/assets/style.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib"
},
"iconLibrary": "lucide"
}---
Top Comments
@gespinha:
After further examination the problem is happening when installing javascript version of the Sidecar component with "typescript": false
- v3 typescript: WORKS
- v3 javascript: FAILS
- v4 typescript: WORKS
- v4 javascript: FAILS
@gespinha:
Logged this as a bug #1463
Version update
Hello, I would like to know if the project will be updated to the current design of the official shadcn project.? Because the current version is not currently in release.
---
Top Comments
@sadeghbarati [maintainer]:
Hey you can check the v4-docs it's in Development and sync with main shadcn ui
Only a bit more time to get v4 ready
Thanks for your patience
@XpPort (+1):
Thanks for the answer
Form or Field Component?
Hello everyone,
As I'm starting a new project with shadcn-vue, I wanted to ask for some guidance on the recommended best practice for building forms. I've noticed we have two great options: the original component family with its convenient, tight integration with vee-validate, and the newer, more flexible <Field /> component family, which seems to align with the future direction of the core shadcn/ui library.
My question is purely about strategy: For new projects, what is the recommended path forward? Is the intention for the community to migrate towards using the <Field /> components, or are both considered equally valid and supported approaches for the foreseeable future?
I'm trying to decide which pattern to adopt for the best long-term maintainability. Thanks for sharing your insights!
Can't resolve 'tw-animate-css'
A one day ago, I encountered a problem when initiating a project using Schadcn-vue + JavaScript. After installing the project and adding a tailwindcss, I received an "[plugin:@tailwindcss/vite:generate:serve] Can't resolve 'tw-animate-css'" error. Could you please advise me on how to resolve this error? The project initiation process was previously the same and there were no problems with it. <img width="855" height="111" alt="error" src="https://github.com/user-attachments/assets/65924bc4-72c4-440c-858d-28d273f6c6c3" />
---
Top Comments
@fontanaen:
Did you add @import "tw-animate-css"; into your style.css ?
Also install tw-animate-css package
I think this is missing from actual doc
<img width="701" height="348" alt="image" src="https://github.com/user-attachments/assets/94fc7cd0-9378-481e-aa8a-555d2951bd6c" />
Have tags input disappeared?
Does anyoane know about tags input? It seem have disappeared from the documentation :(
---
Accepted Answer
@sadeghbarati [maintainer]:
No, we will add it back for now check
https://v3.shadcn-vue.com/docs/components/tags-input.html
Custom registry server
Hello,
I'm trying to setup my own registry server. I've got blocks that includes various .ts and .vue files.
When I use the following example it doesn't install nothing
{
"$schema": "https://shadcn-vue.com/schema/registry-item.json",
"name": "banner",
"type": "registry:ui",
"dependencies": ["lucide-vue-next"],
"files": [
{
"path": "banner/Hello.vue",
"type": "registry:component",
"target": "src/components/ui-shadcnvueforge/banner/Hello.vue"
}
]
}If I add "content": "<template>...</template>" it install the component but install it into on root in components/ui-shadcnvueforge/banner/Hello.vue instead of src/components/ui-shadcnvueforge/banner/Hello.vue
Moreover what is the goal of "path" attribute ? To b...
Docs Index
- About: shadcn-vue is a port of shadcn/ui for Vue/Nuxt. It's maintained by unovue.
- Charts: Legacy: Component will be moved to extended repo with Tailwind v4 support.
- Contribution: Thanks for your interest in contributing to shadcn-vue.com. We're happy to have you here.
- Tailwind v4: It's here! Tailwind v4. Ready for you to try out. You can start using it today.
- Typography
- Introduction: This is not a component library. It is how you build your component library.
- Components
- Installation: Start by selecting your framework of choice. Then follow the instructions to install the dependencies and structure your app. shadcn-vue is built t...
- components.json: The components.json file holds configuration for your project.
- Theming: ::vue-school-link{lesson="theming-with-shadcn-vue" placement="top"}
Watch a Vue School video about theming with shadcn-vue. ::
- Dark Mode
- CLI: Use the init command to initialize configuration and dependencies for a new project.
- JavaScript: This project and the components are written in TypeScript. We recommend using TypeScript for your project as well.
- Figma: Note: The Figma files are contributed by the community. If you have any
questions or feedback, please reach out to the Figma file maintainers.
- Legacy Docs: You're looking at the docs for shadcn-vue + Tailwind v4. If you're looking for the docs for shadcn/ui + Tailwind v3, you can find them here.
- Forms: Start by selecting your framework. Then follow the instructions to learn how to build forms with shadcn-vue and the form library of your choice.
- MCP Server: The shadcn MCP Server allows AI assistants to interact with items from registries. You can browse available components, search for specific ones, a...
components (64)
- Accordion: ::
- Alert Dialog: ::
- Alert: ::
- Aspect Ratio: ::
- Avatar: ::
- Badge: ::
- Breadcrumb: ::
- Button Group: ::
- Button: ::
- Calendar: ::
- Card: ::
- Carousel: ::
- Chart: ::
- Checkbox: ::
- Collapsible: ::
- Combobox: ::
- Command: ::
- Context Menu: ::
- Data Table: ::
- Date Picker: ::
- Dialog: ::
- Drawer: ::
- Dropdown Menu: ::
- Empty: ::
- Field: ::
- Form: ::callout{title="We are not actively developing this component anymore."}
- Hover Card: ::
- Input Group: ::
- Input OTP: ::
- Input: ::
- Item: The Item component is a straightforward flex container that can house nearly any type of content. Use it to display a title, description, and actio...
- Kbd: ::
- Label: ::
- Menubar: ::
- Native Select: For a styled select component, see the Select component.
::
- Navigation Menu: ::
- Number Field: ::
- Pagination: ::
- Pin Input: See the input otp documentation for more information.
- Popover: ::
- Progress: ::
- Radio Group: ::
- Range Calendar: ::
- Resizable: ::
- Scroll Area: ::
- Select: ::
- Separator: ::
- Sheet: ::
- Sidebar: ::
- Skeleton: ::
- Slider: ::
- Sonner: ::
- Spinner: ::
- Stepper: ::
- Switch: ::
- Table: ::
- Tabs: ::
- Tags Input: ::
- Textarea: ::
- Toast: See the sonner documentation for more information.
- Toggle Group: ::
- Toggle: ::
- Tooltip: ::
- Typography: We do not ship any typography styles by default. This page is an example of how you can use utility classes to style your text.
dark-mode (4)
- Vite: ::vue-school-link{lesson="dark-mode-with-shadcn-vue" placement="top"}
Watch a Vue School video about how to enable dark mode with shadcn-vue. ::
- Nuxt: Then, add @nuxtjs/color-mode to the modules section of your nuxt.config.ts
- Vitepress: Optional, to include icons for theme button.
- Astro: Optional, to include icons for theme button.
forms (2)
- VeeValidate: In this guide, we will take a look at building forms with VeeValidate. We'll cover building forms with the <Field /> component, adding schema valid...
- TanStack Form: This guide explores how to build forms using TanStack Form. You'll learn to create forms with <Field /> components, implement schema validation wit...
installation (5)
- Vite: ::vue-school-link{lesson="install-shadcn-vue" placement="top"}
Watch a Vue School video on how to install shadcn-vue. ::
- Nuxt: Start by creating a new Nuxt project using create-nuxt-app:
- Astro: Start by creating a new Astro project:
- Laravel: Start by creating a new Laravel project with Inertia and Vue using the laravel installer laravel new my-app:
- Manual Installation: Components are styled using Tailwind CSS. You need to install Tailwind CSS in your project.
registry (6)
- Examples: The following registry item is a custom style that extends shadcn-vue. On npx shadcn-vue init, it will:
- FAQ: Here's an example of a complex component that installs a page, two components, a composable, a format date utils and a config file.
- Getting Started: This guide will walk you through the process of setting up your own component registry.
- Registry: Note: This feature is currently experimental. Help us improve it by
testing it out and sending feedback. If you have any questions, please reach ou...
- registry-item.json: The registry-item.json schema is used to define your custom registry items.
- registry.json: The registry.json schema is used to define your custom component registry.
About
shadcn-vue is a port of shadcn/ui for Vue/Nuxt. It's maintained by unovue.
Credits
- shadcn - The brilliant mind behind the designs, methodology, and implementation of the original shadcn/ui.
- Reka UI - The headless components that power this project.
- Radix UI - The headless components and examples that the original shadcn/ui was built on.
- Shu Ding - The typography style is adapted from his work on Nextra.
- Cal - Where shad copied the styles for the first component: the
Button.
License
MIT shadcn & unovue
<Callout>
Legacy: Component will be moved to extended repo with Tailwind v4 support.
---
Only works with Vue >3.3
</Callout>
Charts components were built on top of Unovis (a modular data visualization framework), and inspired by tremor.
Chart type
<div class="grid gap-4 mt-8 sm:grid-cols-2 sm:gap-6 not-docs"> <LinkedCard href="/docs/charts/area"> <Area class="text-foreground/80 w-11 h-11" /> <p class="mt-2 font-medium">Area</p> </LinkedCard>
<LinkedCard href="/docs/charts/line"> <Line class="text-foreground/80 w-11 h-11" /> <p class="mt-2 font-medium">Line</p> </LinkedCard>
<LinkedCard href="/docs/charts/bar"> <Bar class="text-foreground/80 w-11 h-11" /> <p class="mt-2 font-medium">Bar</p> </LinkedCard>
<LinkedCard href="/docs/charts/donut"> <Pie class="text-foreground/80 w-11 h-11" /> <p class="mt-2 font-medium">Donut</p> </LinkedCard> </div>
Installation
<Steps>
Update css
Add the following tooltip styling to your tailwind.css file:
@layer base {
:root {
/* ... */
--vis-tooltip-background-color: none !important;
--vis-tooltip-border-color: none !important;
--vis-tooltip-text-color: none !important;
--vis-tooltip-shadow-color: none !important;
--vis-tooltip-backdrop-filter: none !important;
--vis-tooltip-padding: none !important;
--vis-primary-color: var(--primary);
/* change to any hsl value you want */
--vis-secondary-color: 160 81% 40%;
--vis-text-color: var(--muted-foreground);
}
}If you are not using css-variables for your component, you need to update the --vis-primary-color and --vis-text-color to your desired hsl value.
You may use this tool to help you find the hsl value for your primary color and text color. Be sure to provide dark mode styling as well.
</Steps>
Colors
By default, we construct the primary theme color, and secondary (--vis-secondary-color) color with different opacity for the graph.
However, you can always pass in the desired color into each chart.
<template>
<AreaChart
:data="data"
:colors="['blue', 'pink', 'orange', 'red']"
/>
</template>Custom tooltip
If you want to customize the Tooltip for the chart, you can pass customTooltip prop with a custom Vue component. The custom component would receive title and data props, check out ChartTooltip.vue component for example.
The expected prop definition would be:
defineProps<{
title?: string
data: {
name: string
color: string
value: any
}[]
}>()Introduction
Thanks for your interest in contributing to shadcn-vue.com. We're happy to have you here.
Please take a moment to review this document before submitting your first pull request. We also strongly recommend that you check for open issues and pull requests to see if someone else is working on something similar.
If you need any help, feel free to reach out to the core team on Discord.
This guide provides detailed information to help new contributors.
About this repository
This repository is a monorepo.
- We use pnpm and
workspacesfor development.
Project Structure
The GitHub repository consists of the several folders. here's a quick view.
1. packages - Contains source code for supporting nuxt as a module and the cli to add new components.
2. apps/www - The main folder that holds the source code for the website and every shadcn/vue component. This folder contains important sub-folders and is a subproject with its own package.json.
3. .vitepress - Contains the configuration and source code for vitepress and the shadcn/vue website.
4. src - Hosts the main source code for every shadcn/vue component or demo and their documentation on the website.
5. \_\_registry\_\_ - Holds the registry file generated by scripts/build-registry.ts to serve components for the cli. This folder's content is auto-generated and should not be edited manually.
6. scripts - Contains various helper scripts, such as build-registry.ts, which automatically generates the __registry__ folder.
7. content - This folder holds all the documentation for the /docs route. Each component has one .md file documenting the installation and usage of the component.
8. examples - Holds all examples not part of /docs, like the main page.
9. registry - The main folder hosts the source code for different styles of every component. This is likely the main folder you'll be changing.
We support two different styles for every component in shadcn/vue:
1. Default 2. New York
Every component added to the repository must support both versions, including the main source code and associated demos.
When adding or modifying components, please ensure that:
1. You make the changes for every style. 2. You update the documentation. 3. You run pnpm build:registry to update the registry.
Development
Start by cloning the repository:
git clone git@github.com:unovue/shadcn-vue.gitInstall dependencies
pnpm installRun a workspace
You can use the pnpm --filter=[WORKSPACE] command to start the development process for a workspace or some of the shortcut command that we have setup.
Examples
1. To run the shadcn-vue.com website:
pnpm dev2. To run the shadcn-vue cli package:
pnpm dev:cliDocumentation
The documentation for this project is located in the www workspace. You can run the documentation locally by running the following command:
pnpm devDocumentation is written using md. You can find the documentation files in the apps/www/src/content directory.
CLI
The shadcn-vue package is a CLI for adding components to your project. You can find the documentation for the CLI here.
Any changes to the CLI should be made in the packages/cli directory. If you can, it would be great if you could add tests for your changes.
Testing
Tests are written using Vitest. You can run all the tests from the root of the repository.
pnpm testPlease ensure that the tests are passing when submitting a pull request. If you're adding new features, please include tests.
Commit Convention
Before you create a Pull Request, please check whether your commits comply with the commit conventions used in this repository.
When you create a commit we kindly ask you to follow the convention category(scope or module): message in your commit message while using one of the following categories:
feat / feature: all changes that introduce completely new code or new
features
fix: changes that fix a bug (ideally you will additionally reference an
issue if present)
refactor: any code related change that is not a fix nor a featuredocs: changing existing or creating new documentation (i.e. README, docs for
usage of a lib or cli usage)
build: all changes regarding the build of the software, changes to
dependencies or the addition of new dependencies
test: all changes regarding tests (adding new tests or changing existing
ones)
ci: all changes regarding the configuration of continuous integration (i.e.
github actions, ci system)
chore: all changes to the repository that do not fit into any of the above
categories
e.g. feat(components): add new prop to the avatar component
If you are interested in the detailed specification you can visit Conventional Commits.
SFC - Single File Components
Multiple components are integrated into one file in shadcn/ui - the React version of shadcn - while Vue only supports one component per file, hence the name Single File Component (SFC). In such cases, you need to create separate files for each component part and then export them all in an index.ts file.
See the Accordion source code as an example.
Wrapping Reka UI Components
Reka UI hosts many low-level UI components that are used to build reusable components. There are many cases that you need to wrap Reka UI components.
Props & Events
All of the Reka UI components expose their prop and emit types. We need to forward any props/events that are coming from outside to the Reka UI component.
To do so, we have a helper function named useForwardPropsEmits that combines props and events that must be binded to the child radix component.
To be more clear, the function useForwardPropsEmits takes in props and an optional emit function, and returns a computed object that combines the parsed props and emits as props.
Here's an example from Accordion root component.
<script setup lang="ts">
import {
AccordionRoot,
type AccordionRootEmits,
type AccordionRootProps,
useForwardPropsEmits,
} from 'reka-ui'
const props = defineProps<AccordionRootProps>()
const emits = defineEmits<AccordionRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<AccordionRoot v-bind="forwarded">
<slot />
</AccordionRoot>
</template>As you can see, AccordionRootEmits and AccordionRootProps types are imported from radix, combined with useForwardPropsEmits and then are binded using v-bind syntax.
CSS Classes
There are cases when we want to accept class as a prop in our shadcn/vue component and then combine it with a default tailwind class on our Reka UI component via cn utility function.
In these cases, we can not use v-bind, because this would lead in double class binding.
Take a look at DrawerDescription.vue.
<script lang="ts" setup>
import type { DrawerDescriptionProps } from 'vaul-vue'
import type { HTMLAttributes } from 'vue'
import { DrawerDescription } from 'vaul-vue'
import { cn } from '@/lib/utils'
const props = defineProps<DrawerDescriptionProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
</script>
<template>
<DrawerDescription v-bind="delegatedProps" :class="cn('text-sm text-muted-foreground', props.class)">
<slot />
</DrawerDescription>
</template>As you can see, we have created a computed property named delegatedProps to remove class from props, and only then bind the returned value to our radix component (DrawerDescription in this case).
As for our class, we first declared it as type of HTMLAttributes['class'] and used cn to merge tailwind classes from class prop and our own classes.
This pattern only needs to be applied when the cn utility is required. For instances where there are no default Tailwind classes that need to be merged with user-provided classes, this pattern is not necessary. A good example of this is the SelectValue.vue component.
<script setup lang="ts">
import { SelectValue, type SelectValueProps } from 'reka-ui'
const props = defineProps<SelectValueProps>()
</script>
<template>
<SelectValue v-bind="props">
<slot />
</SelectValue>
</template>Boolean Props
When you are building a wrapper for a component, in some cases you want to ignore Vue Props Boolean Casting. You can either set default value as undefined for all the boolean field, or you can use useForwardProps composable.
Take a look at AccordionItem.vue
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { AccordionItem, type AccordionItemProps, useForwardProps } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = defineProps<AccordionItemProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
const forwardedProps = useForwardProps(delegatedProps)
</script>
<template>
<AccordionItem
v-bind="forwardedProps"
:class="cn('border-b', props.class)"
>
<slot />
</AccordionItem>
</template>Since AccordionItemProps type has atleast one boolean property, we need to use useForwardProps on the entire props object.
Note that useForwardPropsEmits use useForwardProps under the hood.
Component as Root
Whenever your root component is a Component Primitive from vue, it's easier to use Primitive instead.
Let's take a look at Button.vue
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { Primitive, type PrimitiveProps } from 'reka-ui'
import { cn } from '@/lib/utils'
import { type ButtonVariants, buttonVariants } from '.'
interface Props extends PrimitiveProps {
variant?: ButtonVariants['variant']
size?: ButtonVariants['size']
class?: HTMLAttributes['class']
}
const props = withDefaults(defineProps<Props>(), {
as: 'button',
})
</script>
<template>
<Primitive
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"
>
<slot />
</Primitive>
</template>You'll need to extend PrimitiveProps in your props to support Primitive component. In most cases you would also need a default value for as property.
Updating with shadcn/ui
shadcn/vue is an unofficial, community-led Vue port of shadcn/ui, as time goes by, they might get out of sync.
As of today, we are in sync with this <a :href="latestSyncCommitUrl" target="_blank">commit</a> of shadcn/ui.
Click on the following link to check if there are newer commits that we should be synced with.
<div class="text-center"> <a :href="diffUrl" target="_blank"> <Button> Check Diff </Button> </a> </div>
1. There are no changes - If you see "There isn’t anything to compare", nothing needs to be done as we are synced with latest version. 2. If there are changes, you should review thoese changes and try to apply them on shadcn/vue codebase and create a PR, remember to update the latestSyncCommitTag in this file too.
Debugging
Here are some tools and techniques that can help you debug more effectively while contributing to shadcn/vue or developing your own projects.
Install Vue Dev Tools
To easily inspect component props, attributes, events, and more, you can leverage the Vue DevTools extension for browsers. This extension provides a user-friendly interface for debugging Vue components and can improve your development experience.
Enable Custom Formmaters
Vue wraps values stored in a ref in a way that, when logged, results in a nested object and requires manual inspection to access the value stored in the ref.
You can enable Custom Formatters in your browser to automate this process.
- Firefox
- Chrome, Edge, Brave and other Chromium based browsers
It's here! Tailwind v4. Ready for you to try out. You can start using it today.
<div class="flex gap-2 items-center mt-6 not-docs"> <Button asChild size="sm" class="rounded-lg"> <a href="#try-it-out">Get Started</a> </Button> <Button asChild size="sm" variant="outline" class="rounded-lg"> <a href="https://v4.shadcn-vue.com" target="_blank" rel="noopener noreferrer"> See Demo </a> </Button> </div>
What's New
- The CLI can now initialize projects with Tailwind v4.
- Full support for the new
@themedirective and@theme inlineoption. - All components are updated for Tailwind v4.
- Every primitive now has a
data-slotattribute for styling. - We've fixed and cleaned up the style of the components.
- We're deprecating the
toastcomponent in favor ofsonner. - Buttons now use the default cursor.
- We're deprecating the
defaultstyle. New projects will usenew-york. - HSL colors are now converted to OKLCH.
Note: this is non-breaking. Your existing apps with Tailwind v3 will still work. When you add new components, they'll still be in v3 until you upgrade. Only new projects start with Tailwind v4.
See it Live
I put together a demo with all the updated components here: https://v4.shadcn-vue.com
Take a look and test the components. If you find any bugs, please let me know on GitHub.
Try It Out
See the framework specific guides below for how to get started.
<div class="grid gap-4 mt-8 sm:grid-cols-2 sm:gap-6 not-docs"> <LinkedCard href="/docs/installation/vite"> <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" fill="currentColor" > <title>Vite</title> <path d="m8.286 10.578.512-8.657a.306.306 0 0 1 .247-.282L17.377.006a.306.306 0 0 1 .353.385l-1.558 5.403a.306.306 0 0 0 .352.385l2.388-.46a.306.306 0 0 1 .332.438l-6.79 13.55-.123.19a.294.294 0 0 1-.252.14c-.177 0-.35-.152-.305-.369l1.095-5.301a.306.306 0 0 0-.388-.355l-1.433.435a.306.306 0 0 1-.389-.354l.69-3.375a.306.306 0 0 0-.37-.36l-2.32.536a.306.306 0 0 1-.374-.316zm14.976-7.926L17.284 3.74l-.544 1.887 2.077-.4a.8.8 0 0 1 .84.369.8.8 0 0 1 .034.783L12.9 19.93l-.013.025-.015.023-.122.19a.801.801 0 0 1-.672.37.826.826 0 0 1-.634-.302.8.8 0 0 1-.16-.67l1.029-4.981-1.12.34a.81.81 0 0 1-.86-.262.802.802 0 0 1-.165-.67l.63-3.08-2.027.468a.808.808 0 0 1-.768-.233.81.81 0 0 1-.217-.6l.389-6.57-7.44-1.33a.612.612 0 0 0-.64.906L11.58 23.691a.612.612 0 0 0 1.066-.004l11.26-20.135a.612.612 0 0 0-.644-.9z" /> </svg> <p class="mt-2 font-medium">Vite</p> </LinkedCard> <LinkedCard href="/docs/installation/nuxt"> <svg xmlns="http://www.w3.org/2000/svg" class="w-12 h-12" viewBox="0 0 900 900" fill="none"> <title>Nuxt</title> <path d="M504.908 750H839.476C850.103 750.001 860.542 747.229 869.745 741.963C878.948 736.696 886.589 729.121 891.9 719.999C897.211 710.876 900.005 700.529 900 689.997C899.995 679.465 897.193 669.12 891.873 660.002L667.187 274.289C661.876 265.169 654.237 257.595 645.036 252.329C635.835 247.064 625.398 244.291 614.773 244.291C604.149 244.291 593.711 247.064 584.511 252.329C575.31 257.595 567.67 265.169 562.36 274.289L504.908 372.979L392.581 179.993C387.266 170.874 379.623 163.301 370.42 158.036C361.216 152.772 350.777 150 340.151 150C329.525 150 319.086 152.772 309.883 158.036C300.679 163.301 293.036 170.874 287.721 179.993L8.12649 660.002C2.80743 669.12 0.00462935 679.465 5.72978e-06 689.997C-0.00461789 700.529 2.78909 710.876 8.10015 719.999C13.4112 729.121 21.0523 736.696 30.255 741.963C39.4576 747.229 49.8973 750.001 60.524 750H270.538C353.748 750 415.112 713.775 457.336 643.101L559.849 467.145L614.757 372.979L779.547 655.834H559.849L504.908 750ZM267.114 655.737L120.551 655.704L340.249 278.586L449.87 467.145L376.474 593.175C348.433 639.03 316.577 655.737 267.114 655.737Z" fill="currentColor"/> </svg> <p class="mt-2 font-medium">Nuxt</p> </LinkedCard> <LinkedCard href="/docs/installation/astro"> <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" fill="currentColor" > <title>Astro</title> <path d="M16.074 16.86C15.354 17.476 13.917 17.895 12.262 17.895C10.23 17.895 8.527 17.263 8.075 16.412C7.914 16.9 7.877 17.458 7.877 17.814C7.877 17.814 7.771 19.564 8.988 20.782C8.988 20.15 9.501 19.637 10.133 19.637C11.216 19.637 11.215 20.582 11.214 21.349V21.418C11.214 22.582 11.925 23.579 12.937 24C12.7812 23.6794 12.7005 23.3275 12.701 22.971C12.701 21.861 13.353 21.448 14.111 20.968C14.713 20.585 15.383 20.161 15.844 19.308C16.0926 18.8493 16.2225 18.3357 16.222 17.814C16.2221 17.4903 16.1722 17.1685 16.074 16.86ZM15.551 0.6C15.747 0.844 15.847 1.172 16.047 1.829L20.415 16.176C18.7743 15.3246 17.0134 14.7284 15.193 14.408L12.35 4.8C12.3273 4.72337 12.2803 4.65616 12.2162 4.60844C12.152 4.56072 12.0742 4.53505 11.9943 4.53528C11.9143 4.5355 11.8366 4.56161 11.7727 4.60969C11.7089 4.65777 11.6623 4.72524 11.64 4.802L8.83 14.405C7.00149 14.724 5.23264 15.3213 3.585 16.176L7.974 1.827C8.174 1.171 8.274 0.843 8.471 0.6C8.64406 0.385433 8.86922 0.218799 9.125 0.116C9.415 0 9.757 0 10.443 0H13.578C14.264 0 14.608 0 14.898 0.117C15.1529 0.219851 15.3783 0.386105 15.551 0.6Z" fill="currentColor" /> </svg> <p class="mt-2 font-medium">Astro</p> </LinkedCard> <LinkedCard href="/docs/installation/laravel"> <svg role="img" viewBox="0 0 62 65" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" > <path d="M61.8548 14.6253C61.8778 14.7102 61.8895 14.7978 61.8897 14.8858V28.5615C61.8898 28.737 61.8434 28.9095 61.7554 29.0614C61.6675 29.2132 61.5409 29.3392 61.3887 29.4265L49.9104 36.0351V49.1337C49.9104 49.4902 49.7209 49.8192 49.4118 49.9987L25.4519 63.7916C25.3971 63.8227 25.3372 63.8427 25.2774 63.8639C25.255 63.8714 25.2338 63.8851 25.2101 63.8913C25.0426 63.9354 24.8666 63.9354 24.6991 63.8913C24.6716 63.8838 24.6467 63.8689 24.6205 63.8589C24.5657 63.8389 24.5084 63.8215 24.456 63.7916L0.501061 49.9987C0.348882 49.9113 0.222437 49.7853 0.134469 49.6334C0.0465019 49.4816 0.000120578 49.3092 0 49.1337L0 8.10652C0 8.01678 0.0124642 7.92953 0.0348998 7.84477C0.0423783 7.8161 0.0598282 7.78993 0.0697995 7.76126C0.0884958 7.70891 0.105946 7.65531 0.133367 7.6067C0.152063 7.5743 0.179485 7.54812 0.20192 7.51821C0.230588 7.47832 0.256763 7.43719 0.290416 7.40229C0.319084 7.37362 0.356476 7.35243 0.388883 7.32751C0.425029 7.29759 0.457436 7.26518 0.498568 7.2415L12.4779 0.345059C12.6296 0.257786 12.8015 0.211853 12.9765 0.211853C13.1515 0.211853 13.3234 0.257786 13.475 0.345059L25.4531 7.2415H25.4556C25.4955 7.26643 25.5292 7.29759 25.5653 7.32626C25.5977 7.35119 25.6339 7.37362 25.6625 7.40104C25.6974 7.43719 25.7224 7.47832 25.7523 7.51821C25.7735 7.54812 25.8021 7.5743 25.8196 7.6067C25.8483 7.65656 25.8645 7.70891 25.8844 7.76126C25.8944 7.78993 25.9118 7.8161 25.9193 7.84602C25.9423 7.93096 25.954 8.01853 25.9542 8.10652V33.7317L35.9355 27.9844V14.8846C35.9355 14.7973 35.948 14.7088 35.9704 14.6253C35.9792 14.5954 35.9954 14.5692 36.0053 14.5405C36.0253 14.4882 36.0427 14.4346 36.0702 14.386C36.0888 14.3536 36.1163 14.3274 36.1375 14.2975C36.1674 14.2576 36.1923 14.2165 36.2272 14.1816C36.2559 14.1529 36.292 14.1317 36.3244 14.1068C36.3618 14.0769 36.3942 14.0445 36.4341 14.0208L48.4147 7.12434C48.5663 7.03694 48.7383 6.99094 48.9133 6.99094C49.0883 6.99094 49.2602 7.03694 49.4118 7.12434L61.3899 14.0208C61.4323 14.0457 61.4647 14.0769 61.5021 14.1055C61.5333 14.1305 61.5694 14.1529 61.5981 14.1803C61.633 14.2165 61.6579 14.2576 61.6878 14.2975C61.7103 14.3274 61.7377 14.3536 61.7551 14.386C61.7838 14.4346 61.8 14.4882 61.8199 14.5405C61.8312 14.5692 61.8474 14.5954 61.8548 14.6253ZM59.893 27.9844V16.6121L55.7013 19.0252L49.9104 22.3593V33.7317L59.8942 27.9844H59.893ZM47.9149 48.5566V37.1768L42.2187 40.4299L25.953 49.7133V61.2003L47.9149 48.5566ZM1.99677 9.83281V48.5566L23.9562 61.199V49.7145L12.4841 43.2219L12.4804 43.2194L12.4754 43.2169C12.4368 43.1945 12.4044 43.1621 12.3682 43.1347C12.3371 43.1097 12.3009 43.0898 12.2735 43.0624L12.271 43.0586C12.2386 43.0275 12.2162 42.9888 12.1887 42.9539C12.1638 42.9203 12.1339 42.8916 12.114 42.8567L12.1127 42.853C12.0903 42.8156 12.0766 42.7707 12.0604 42.7283C12.0442 42.6909 12.023 42.656 12.013 42.6161C12.0005 42.5688 11.998 42.5177 11.9931 42.4691C11.9881 42.4317 11.9781 42.3943 11.9781 42.3569V15.5801L6.18848 12.2446L1.99677 9.83281ZM12.9777 2.36177L2.99764 8.10652L12.9752 13.8513L22.9541 8.10527L12.9752 2.36177H12.9777ZM18.1678 38.2138L23.9574 34.8809V9.83281L19.7657 12.2459L13.9749 15.5801V40.6281L18.1678 38.2138ZM48.9133 9.14105L38.9344 14.8858L48.9133 20.6305L58.8909 14.8846L48.9133 9.14105ZM47.9149 22.3593L42.124 19.0252L37.9323 16.6121V27.9844L43.7219 31.3174L47.9149 33.7317V22.3593ZM24.9533 47.987L39.59 39.631L46.9065 35.4555L36.9352 29.7145L25.4544 36.3242L14.9907 42.3482L24.9533 47.987Z" /> </svg> <p class="mt-2 font-medium">Laravel</p> </LinkedCard> <LinkedCard href="/docs/installation/manual"> <svg class="w-10 h-10" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M19.114 2H15l-3 4.9L9.429 2H0l12 21L24 2zM3 3.75h2.914L12 14.6l6.086-10.85H21L12 19.5z"/></svg> <p class="mt-2 font-medium">Manual</p> </LinkedCard> </div>
Upgrade Your Project
<Callout class="bg-blue-50 mt-6 border-blue-600 dark:border-blue-900 dark:bg-blue-950 mb-6 [&_code]:bg-blue-100 dark:[&_code]:bg-blue-900 [&_a]:underline [&_a]:underline-offset-4">
Important: Before upgrading, please read the Tailwind v4 Compatibility Docs and make sure your project is ready for the upgrade. Tailwind v4 uses bleeding-edge browser features and is designed for modern browsers.
</Callout>
One of the major advantages of using shadcn-vue is that the code you end up with is exactly what you'd write yourself. There are no hidden abstractions.
This means when a dependency has a new release, you can just follow the official upgrade paths.
Here's how to upgrade your existing projects (full docs are on the way):
1. Follow the Tailwind v4 Upgrade Guide
- Upgrade to Tailwind v4 by following the official upgrade guide: https://tailwindcss.com/docs/upgrade-guide
- Use the
@tailwindcss/upgrade@nextcodemod to remove deprecated utility classes and update tailwind config.
2. Update your CSS variables
The codemod will migrate your CSS variables as references under the @theme directive.
```css showLineNumbers @layer base { :root { --background: 0 0% 100%; --foreground: 0 0% 3.9%; } }
@theme { --color-background: hsl(var(--background)); --color-foreground: hsl(var(--foreground)); }
This works. But to make it easier to work with colors and other variables, we'll need to move the `hsl` wrappers and use `@theme inline`.
Here's how you do it:
1. Move `:root` and `.dark` out of the `@layer` base.
2. Wrap the color values in `hsl()`
3. Add the `inline` option to `@theme` i.e `@theme inline`
4. Remove the `hsl()` wrappers from `@theme`
:root { --background: hsl(0 0% 100%); // <-- Wrap in hsl --foreground: hsl(0 0% 3.9%); }
.dark { --background: hsl(0 0% 3.9%); // <-- Wrap in hsl --foreground: hsl(0 0% 98%); }
@theme inline { --color-background: var(--background); // <-- Remove hsl --color-foreground: var(--foreground); }
This change makes it much simpler to access your theme variables in both utility classes and outside of CSS for eg. using color values in JavaScript.
### 3. Use new `size-*` utility
The new `size-*` utility (added in Tailwind v3.4), is now fully supported by `tailwind-merge`. You can replace `w-* h-*` with the new `size-*` utility:
- w-4 h-4
+ size-4
### 4. Install and Update your dependencies
pnpm i tw-animate-css pnpm up reka-ui lucide-vue-next tailwind-merge clsx --latest
<ComponentPreview name="TypographyDemo" />
h1
<ComponentPreview name="TypographyH1" />
h2
<ComponentPreview name="TypographyH2" />
h3
<ComponentPreview name="TypographyH3" />
h4
<ComponentPreview name="TypographyH4" />
p
<ComponentPreview name="TypographyP" />
blockquote
<ComponentPreview name="TypographyBlockquote" />
table
<ComponentPreview name="TypographyTable" />
list
<ComponentPreview name="TypographyList" />
Inline code
<ComponentPreview name="TypographyInlineCode" />
Lead
<ComponentPreview name="TypographyLead" />
Large
<ComponentPreview name="TypographyLarge" />
Small
<ComponentPreview name="TypographySmall" />
Muted
<ComponentPreview name="TypographyMuted" />
This is not a component library. It is how you build your component library.
::vue-school-link{lesson="what-is-shadcn-vue" placement="top"} Watch a Vue School intro video about shadcn-vue. ::
You know how most traditional component libraries work: you install a package from NPM, import the components, and use them in your app.
This approach works well until you need to customize a component to fit your design system or require one that isn't included in the library. Often, you end up wrapping library components, writing workarounds to override styles, or mixing components from different libraries with incompatible APIs.
This is what shadcn-vue aims to solve. It is built around the following principles:
- Open Code: The top layer of your component code is open for modification.
- Composition: Every component uses a common, composable interface, making them predictable.
- Distribution: A flat-file schema and command-line tool make it easy to distribute components.
- Beautiful Defaults: Carefully chosen default styles, so you get great design out-of-the-box.
- AI-Ready: Open code for LLMs to read, understand, and improve.
Open Code
shadcn-vue hands you the actual component code. You have full control to customize and extend the components to your needs. This means:
- Full Transparency: You see exactly how each component is built.
- Easy Customization: Modify any part of a component to fit your design and functionality requirements.
- AI Integration: Access to the code makes it straightforward for LLMs to read, understand, and even improve your components.
_In a typical library, if you need to change a button's behavior, you have to override styles or wrap the component. With shadcn-vue, you simply edit the button code directly._
<accordion collapsible> <accordion-item value="faq-1" class="border-none"> <accordion-trigger> How do I pull upstream updates in an Open Code approach? </accordion-trigger> <accordion-content> <p> shadcn-vue follows a headless component architecture. This means the core of your app can receive fixes by updating your dependencies, for instance, radix-ui or input-otp. </p> <p class="mt-4"> The topmost layer, i.e., the one closest to your design system, is not coupled with the implementation of the library. It stays open for modification. </p> </accordion-content> </accordion-item> </accordion>
Composition
Every component in shadcn-vue shares a common, composable interface. If a component does not exist, we bring it in, make it composable, and adjust its style to match and work with the rest of the design system.
_A shared, composable interface means it's predictable for both your team and LLMs. You are not learning different APIs for every new component. Even for third-party ones._
Distribution
shadcn-vue is also a code distribution system. It defines a schema for components and a CLI to distribute them.
- Schema: A flat-file structure that defines the components, their dependencies, and properties.
- CLI: A command-line tool to distribute and install components across projects with cross-framework support.
_You can use the schema to distribute your components to other projects or have AI generate completely new components based on existing schema._
Beautiful Defaults
shadcn-vue comes with a large collection of components that have carefully chosen default styles. They are designed to look good on their own and to work well together as a consistent system:
- Good Out-of-the-Box: Your UI has a clean and minimal look without extra work.
- Unified Design: Components naturally fit with one another. Each component is built to match the others, keeping your UI consistent.
- Easily Customizable: If you want to change something, it's simple to override and extend the defaults.
AI-Ready
The design of shadcn-vue makes it easy for AI tools to work with your code. Its open code and consistent API allow AI models to read, understand, and even generate new components.
_An AI model can learn how your components work and suggest improvements or even create new components that integrate with your existing design._
<ComponentsList />
Pick Your Framework
Start by selecting your framework of choice. Then follow the instructions to install the dependencies and structure your app. shadcn-vue is built to work with all Vue frameworks.
<div class="mt-8 grid gap-4 sm:grid-cols-2 sm:gap-6"> <linked-card href="/docs/installation/vite"> <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" fill="currentColor" > <title>Vite</title> <path d="m8.286 10.578.512-8.657a.306.306 0 0 1 .247-.282L17.377.006a.306.306 0 0 1 .353.385l-1.558 5.403a.306.306 0 0 0 .352.385l2.388-.46a.306.306 0 0 1 .332.438l-6.79 13.55-.123.19a.294.294 0 0 1-.252.14c-.177 0-.35-.152-.305-.369l1.095-5.301a.306.306 0 0 0-.388-.355l-1.433.435a.306.306 0 0 1-.389-.354l.69-3.375a.306.306 0 0 0-.37-.36l-2.32.536a.306.306 0 0 1-.374-.316zm14.976-7.926L17.284 3.74l-.544 1.887 2.077-.4a.8.8 0 0 1 .84.369.8.8 0 0 1 .034.783L12.9 19.93l-.013.025-.015.023-.122.19a.801.801 0 0 1-.672.37.826.826 0 0 1-.634-.302.8.8 0 0 1-.16-.67l1.029-4.981-1.12.34a.81.81 0 0 1-.86-.262.802.802 0 0 1-.165-.67l.63-3.08-2.027.468a.808.808 0 0 1-.768-.233.81.81 0 0 1-.217-.6l.389-6.57-7.44-1.33a.612.612 0 0 0-.64.906L11.58 23.691a.612.612 0 0 0 1.066-.004l11.26-20.135a.612.612 0 0 0-.644-.9z" /> </svg> <p class="mt-2 font-medium [&:not(:first-child)]:mt-2">Vite</p> </linked-card> <linked-card href="/docs/installation/nuxt"> <svg xmlns="http://www.w3.org/2000/svg" class="w-12 h-12" viewBox="0 0 900 900" fill="none"> <title>Nuxt</title> <path d="M504.908 750H839.476C850.103 750.001 860.542 747.229 869.745 741.963C878.948 736.696 886.589 729.121 891.9 719.999C897.211 710.876 900.005 700.529 900 689.997C899.995 679.465 897.193 669.12 891.873 660.002L667.187 274.289C661.876 265.169 654.237 257.595 645.036 252.329C635.835 247.064 625.398 244.291 614.773 244.291C604.149 244.291 593.711 247.064 584.511 252.329C575.31 257.595 567.67 265.169 562.36 274.289L504.908 372.979L392.581 179.993C387.266 170.874 379.623 163.301 370.42 158.036C361.216 152.772 350.777 150 340.151 150C329.525 150 319.086 152.772 309.883 158.036C300.679 163.301 293.036 170.874 287.721 179.993L8.12649 660.002C2.80743 669.12 0.00462935 679.465 5.72978e-06 689.997C-0.00461789 700.529 2.78909 710.876 8.10015 719.999C13.4112 729.121 21.0523 736.696 30.255 741.963C39.4576 747.229 49.8973 750.001 60.524 750H270.538C353.748 750 415.112 713.775 457.336 643.101L559.849 467.145L614.757 372.979L779.547 655.834H559.849L504.908 750ZM267.114 655.737L120.551 655.704L340.249 278.586L449.87 467.145L376.474 593.175C348.433 639.03 316.577 655.737 267.114 655.737Z" fill="currentColor"/> </svg> <p class="mt-2 font-medium [&:not(:first-child)]:mt-2">Nuxt</p> </linked-card> <linked-card href="/docs/installation/astro"> <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" fill="currentColor" > <title>Astro</title> <path d="M16.074 16.86C15.354 17.476 13.917 17.895 12.262 17.895C10.23 17.895 8.527 17.263 8.075 16.412C7.914 16.9 7.877 17.458 7.877 17.814C7.877 17.814 7.771 19.564 8.988 20.782C8.988 20.15 9.501 19.637 10.133 19.637C11.216 19.637 11.215 20.582 11.214 21.349V21.418C11.214 22.582 11.925 23.579 12.937 24C12.7812 23.6794 12.7005 23.3275 12.701 22.971C12.701 21.861 13.353 21.448 14.111 20.968C14.713 20.585 15.383 20.161 15.844 19.308C16.0926 18.8493 16.2225 18.3357 16.222 17.814C16.2221 17.4903 16.1722 17.1685 16.074 16.86ZM15.551 0.6C15.747 0.844 15.847 1.172 16.047 1.829L20.415 16.176C18.7743 15.3246 17.0134 14.7284 15.193 14.408L12.35 4.8C12.3273 4.72337 12.2803 4.65616 12.2162 4.60844C12.152 4.56072 12.0742 4.53505 11.9943 4.53528C11.9143 4.5355 11.8366 4.56161 11.7727 4.60969C11.7089 4.65777 11.6623 4.72524 11.64 4.802L8.83 14.405C7.00149 14.724 5.23264 15.3213 3.585 16.176L7.974 1.827C8.174 1.171 8.274 0.843 8.471 0.6C8.64406 0.385433 8.86922 0.218799 9.125 0.116C9.415 0 9.757 0 10.443 0H13.578C14.264 0 14.608 0 14.898 0.117C15.1529 0.219851 15.3783 0.386105 15.551 0.6Z" fill="currentColor" /> </svg> <p class="mt-2 font-medium [&:not(:first-child)]:mt-2">Astro</p> </linked-card> <linked-card href="/docs/installation/laravel"> <svg role="img" viewBox="0 0 62 65" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" > <path d="M61.8548 14.6253C61.8778 14.7102 61.8895 14.7978 61.8897 14.8858V28.5615C61.8898 28.737 61.8434 28.9095 61.7554 29.0614C61.6675 29.2132 61.5409 29.3392 61.3887 29.4265L49.9104 36.0351V49.1337C49.9104 49.4902 49.7209 49.8192 49.4118 49.9987L25.4519 63.7916C25.3971 63.8227 25.3372 63.8427 25.2774 63.8639C25.255 63.8714 25.2338 63.8851 25.2101 63.8913C25.0426 63.9354 24.8666 63.9354 24.6991 63.8913C24.6716 63.8838 24.6467 63.8689 24.6205 63.8589C24.5657 63.8389 24.5084 63.8215 24.456 63.7916L0.501061 49.9987C0.348882 49.9113 0.222437 49.7853 0.134469 49.6334C0.0465019 49.4816 0.000120578 49.3092 0 49.1337L0 8.10652C0 8.01678 0.0124642 7.92953 0.0348998 7.84477C0.0423783 7.8161 0.0598282 7.78993 0.0697995 7.76126C0.0884958 7.70891 0.105946 7.65531 0.133367 7.6067C0.152063 7.5743 0.179485 7.54812 0.20192 7.51821C0.230588 7.47832 0.256763 7.43719 0.290416 7.40229C0.319084 7.37362 0.356476 7.35243 0.388883 7.32751C0.425029 7.29759 0.457436 7.26518 0.498568 7.2415L12.4779 0.345059C12.6296 0.257786 12.8015 0.211853 12.9765 0.211853C13.1515 0.211853 13.3234 0.257786 13.475 0.345059L25.4531 7.2415H25.4556C25.4955 7.26643 25.5292 7.29759 25.5653 7.32626C25.5977 7.35119 25.6339 7.37362 25.6625 7.40104C25.6974 7.43719 25.7224 7.47832 25.7523 7.51821C25.7735 7.54812 25.8021 7.5743 25.8196 7.6067C25.8483 7.65656 25.8645 7.70891 25.8844 7.76126C25.8944 7.78993 25.9118 7.8161 25.9193 7.84602C25.9423 7.93096 25.954 8.01853 25.9542 8.10652V33.7317L35.9355 27.9844V14.8846C35.9355 14.7973 35.948 14.7088 35.9704 14.6253C35.9792 14.5954 35.9954 14.5692 36.0053 14.5405C36.0253 14.4882 36.0427 14.4346 36.0702 14.386C36.0888 14.3536 36.1163 14.3274 36.1375 14.2975C36.1674 14.2576 36.1923 14.2165 36.2272 14.1816C36.2559 14.1529 36.292 14.1317 36.3244 14.1068C36.3618 14.0769 36.3942 14.0445 36.4341 14.0208L48.4147 7.12434C48.5663 7.03694 48.7383 6.99094 48.9133 6.99094C49.0883 6.99094 49.2602 7.03694 49.4118 7.12434L61.3899 14.0208C61.4323 14.0457 61.4647 14.0769 61.5021 14.1055C61.5333 14.1305 61.5694 14.1529 61.5981 14.1803C61.633 14.2165 61.6579 14.2576 61.6878 14.2975C61.7103 14.3274 61.7377 14.3536 61.7551 14.386C61.7838 14.4346 61.8 14.4882 61.8199 14.5405C61.8312 14.5692 61.8474 14.5954 61.8548 14.6253ZM59.893 27.9844V16.6121L55.7013 19.0252L49.9104 22.3593V33.7317L59.8942 27.9844H59.893ZM47.9149 48.5566V37.1768L42.2187 40.4299L25.953 49.7133V61.2003L47.9149 48.5566ZM1.99677 9.83281V48.5566L23.9562 61.199V49.7145L12.4841 43.2219L12.4804 43.2194L12.4754 43.2169C12.4368 43.1945 12.4044 43.1621 12.3682 43.1347C12.3371 43.1097 12.3009 43.0898 12.2735 43.0624L12.271 43.0586C12.2386 43.0275 12.2162 42.9888 12.1887 42.9539C12.1638 42.9203 12.1339 42.8916 12.114 42.8567L12.1127 42.853C12.0903 42.8156 12.0766 42.7707 12.0604 42.7283C12.0442 42.6909 12.023 42.656 12.013 42.6161C12.0005 42.5688 11.998 42.5177 11.9931 42.4691C11.9881 42.4317 11.9781 42.3943 11.9781 42.3569V15.5801L6.18848 12.2446L1.99677 9.83281ZM12.9777 2.36177L2.99764 8.10652L12.9752 13.8513L22.9541 8.10527L12.9752 2.36177H12.9777ZM18.1678 38.2138L23.9574 34.8809V9.83281L19.7657 12.2459L13.9749 15.5801V40.6281L18.1678 38.2138ZM48.9133 9.14105L38.9344 14.8858L48.9133 20.6305L58.8909 14.8846L48.9133 9.14105ZM47.9149 22.3593L42.124 19.0252L37.9323 16.6121V27.9844L43.7219 31.3174L47.9149 33.7317V22.3593ZM24.9533 47.987L39.59 39.631L46.9065 35.4555L36.9352 29.7145L25.4544 36.3242L14.9907 42.3482L24.9533 47.987Z" /> </svg> <p class="mt-2 font-medium [&:not(:first-child)]:mt-2">Laravel</p> </linked-card> <linked-card href="/docs/installation/manual"> <svg class="w-10 h-10" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M19.114 2H15l-3 4.9L9.429 2H0l12 21L24 2zM3 3.75h2.914L12 14.6l6.086-10.85H21L12 19.5z"/></svg> <p class="mt-2 font-medium [&:not(:first-child)]:mt-2">Manual</p> </linked-card> </div>
VSCode extension
Install the shadcn-vue extension by @selemondev in Visual Studio Code to easily add Shadcn Vue components to your project.
This extension offers a range of features:
- Ability to initialize the Shadcn Vue CLI
- Install components
- Open documentation
- Navigate to a specific component's documentation page directly from your IDE.
- Handy snippets for quick and straightforward component imports and markup.
The components.json file holds configuration for your project.
We use it to understand how your project is set up and how to generate components customized for your project.
<Callout class="mt-6" title="Note: The components.json file is optional">
It is only required if you're using the CLI to add components to your project. If you're using the copy and paste method, you don't need this file.
</Callout>
You can create a components.json file in your project by running the following command:
npx shadcn-vue@latest initSee the CLI section for more information.
$schema
You can see the JSON Schema for components.json here.
```json title="components.json" { "$schema": "https://shadcn-vue.com/schema.json" }
## style
The style for your components. **This cannot be changed after initialization.**
{ "style": "new-york" }
The `default` style has been deprecated. Use the `new-york` style instead.
## tailwind
Configuration to help the CLI understand how Tailwind CSS is set up in your project.
See the <a href="/docs/installation">installation section</a> for how to set up Tailwind CSS.
### tailwind.config
Path to where your `tailwind.config.js` file is located. **For Tailwind CSS v4, leave this blank.**
{ "tailwind": { "config": "tailwind.config.js" | "tailwind.config.ts" } }
### tailwind.css
Path to the CSS file that imports Tailwind CSS into your project.
{ "tailwind": { "css": "styles/global.css" } }
### tailwind.baseColor
This is used to generate the default color palette for your components. **This cannot be changed after initialization.**
{ "tailwind": { "baseColor": "gray" | "neutral" | "slate" | "stone" | "zinc" } }
### tailwind.cssVariables
You can choose between using CSS variables or Tailwind CSS utility classes for theming.
To use utility classes for theming set `tailwind.cssVariables` to `false`. For CSS variables, set `tailwind.cssVariables` to `true`.
{ "tailwind": { "cssVariables": true | false } }
For more information, see the <Link href="/docs/theming">theming docs</Link>.
**This cannot be changed after initialization.** To switch between CSS variables and utility classes, you'll have to delete and re-install your components.
### tailwind.prefix
The prefix to use for your Tailwind CSS utility classes. Components will be added with this prefix.
{ "tailwind": { "prefix": "tw-" } }
## typescript
Choose between TypeScript or JavaScript components.
Setting this option to `false` allows components to be added as JavaScript in `.vue` file.
{ "typescript": true | false }
## aliases
The CLI uses these values and the `paths` config from your `tsconfig.json` or `jsconfig.json` file to place generated components in the correct location.
Path aliases have to be set up in your `tsconfig.json` or `jsconfig.json` file.
<Callout class="mt-6">
**Important:** If you're using the `src` directory, make sure it is included
under `paths` in your `tsconfig.json` or `jsconfig.json` file.
</Callout>
### aliases.utils
Import alias for your utility functions.
{ "aliases": { "utils": "@/lib/utils" } }
### aliases.components
Import alias for your components.
{ "aliases": { "components": "@/components" } }
### aliases.ui
Import alias for `ui` components.
The CLI will use the `aliases.ui` value to determine where to place your `ui` components. Use this config if you want to customize the installation directory for your `ui` components.
{ "aliases": { "ui": "@/app/ui" } }
### aliases.lib
Import alias for `lib` functions such as `cn` or `valueUpdater`.
{ "aliases": { "lib": "@/lib" } }
### aliases.composables
Import alias for `composables` such as `useMediaQuery` or `useToast`.
{ "aliases": { "composables": "@/composables" } }
::vue-school-link{lesson="theming-with-shadcn-vue" placement="top"} Watch a Vue School video about theming with shadcn-vue. ::
<Callout>
Want to build your theme visually? Use shadcn-vue/create to preview colors, radius, fonts, and icons, then generate a preset for your project.
</Callout>
We use and recommend CSS variables for theming.
This gives you semantic theme tokens like background, foreground, and primary that components use by default. Override those tokens in your CSS to change the look of your app without rewriting component classes.
```vue /bg-background/ /text-foreground/ <div class="bg-background text-foreground" />
To use CSS variables for theming, set `tailwind.cssVariables` to `true` in your `components.json` file. This is the default.
{ "style": "default", "typescript": true, "tailwind": { "config": "", "css": "assets/css/tailwind.css", "baseColor": "neutral", "cssVariables": true } }
Tailwind maps these tokens into utilities like `bg-background`, `text-foreground`, `border-border`, and `ring-ring`.
Dark mode works by overriding the same tokens inside a `.dark` selector. See the [dark mode docs](/docs/dark-mode) for adding a theme provider and toggling the `.dark` class.
## Token Convention
We use semantic background and foreground pairs. The base token controls the surface color and the `-foreground` token controls the text and icon color that sits on that surface.
<Callout class="mt-4">
The background suffix is omitted for the surface token. For example, `primary` pairs with `primary-foreground`.
</Callout>
Given the following CSS variables:
--primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0);
The `background` color of the following component will be `var(--primary)` and the `foreground` color will be `var(--primary-foreground)`.
<div class="bg-primary text-primary-foreground">Hello</div>
## Theme Tokens
These tokens live in your CSS file under `:root` and `.dark`.
| Token | What it controls | Used by |
| ------------------------------------------------ | ------------------------------------------------------ | ---------------------------------------------------------------------------- |
| `background` / `foreground` | The default app background and text color. | The page shell, page sections, and default text. |
| `card` / `card-foreground` | Elevated surfaces and the content inside them. | `Card`, dashboard panels, settings panels. |
| `popover` / `popover-foreground` | Floating surfaces and the content inside them. | `Popover`, `DropdownMenu`, `ContextMenu`, and other overlays. |
| `primary` / `primary-foreground` | High-emphasis actions and brand surfaces. | Default `Button`, selected states, badges, and active accents. |
| `secondary` / `secondary-foreground` | Lower-emphasis filled actions and supporting surfaces. | Secondary buttons, secondary badges, and supporting UI. |
| `muted` / `muted-foreground` | Subtle surfaces and lower-emphasis content. | Descriptions, placeholders, empty states, helper text, and subdued surfaces. |
| `accent` / `accent-foreground` | Interactive hover, focus, and active surfaces. | Ghost buttons, menu highlight states, hovered rows, and selected items. |
| `destructive` | Destructive actions and error emphasis. | Destructive buttons, invalid states, and destructive menu items. |
| `border` | Default borders and separators. | Cards, menus, tables, separators, and layout dividers. |
| `input` | Form control borders and input surface treatment. | `Input`, `Textarea`, `Select`, and outline-style controls. |
| `ring` | Focus rings and outlines. | Buttons, inputs, checkboxes, menus, and other focusable controls. |
| `chart-1` ... `chart-5` | The default chart palette. | Charts and chart-driven dashboard blocks. |
| `sidebar` / `sidebar-foreground` | The base sidebar surface and default sidebar text. | The `Sidebar` container and its default content. |
| `sidebar-primary` / `sidebar-primary-foreground` | High-emphasis actions inside the sidebar. | Active items, icon tiles, badges, and sidebar CTAs. |
| `sidebar-accent` / `sidebar-accent-foreground` | Hover and selected states inside the sidebar. | Sidebar menu hover states, open items, and interactive rows. |
| `sidebar-border` | Sidebar-specific borders and separators. | Sidebar headers, groups, and internal dividers. |
| `sidebar-ring` | Sidebar-specific focus rings. | Focused controls inside the sidebar. |
| `radius` | The base corner radius scale. | Cards, inputs, buttons, popovers, and the derived `radius-*` tokens. |
<Callout class="mt-4">
The chart tokens are covered in more detail in the [Chart theming docs](/docs/components/chart#theming).
</Callout>
## Radius Scale
`--radius` is the base radius token for your theme.
We derive a small radius scale from it so components can use consistent corner sizes while still sharing a single source of truth.
@theme inline { --radius-sm: calc(var(--radius) 0.6); --radius-md: calc(var(--radius) 0.8); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) 1.4); --radius-2xl: calc(var(--radius) 1.8); --radius-3xl: calc(var(--radius) 2.2); --radius-4xl: calc(var(--radius) 2.6); }
This means:
- `radius-lg` is the base value.
- Smaller radii scale down from `--radius`.
- Larger radii scale up from `--radius`.
- Changing `--radius` updates the entire radius scale.
## Adding New Tokens
To add a new token, define it under `:root` and `.dark`, then expose it to Tailwind with `@theme inline`.
:root { --warning: oklch(0.84 0.16 84); --warning-foreground: oklch(0.28 0.07 46); }
.dark { --warning: oklch(0.41 0.11 46); --warning-foreground: oklch(0.99 0.02 95); }
@theme inline { --color-warning: var(--warning); --color-warning-foreground: var(--warning-foreground); }
You can now use `bg-warning` and `text-warning-foreground` in your components.
<div class="bg-warning text-warning-foreground" />
## Base Colors
`tailwind.baseColor` controls the default token values generated for your project when you run `init` or use a preset.
The available base colors are: **Neutral**, **Gray**, **Zinc**, **Stone**, and **Slate**.
## Default Theme CSS
The following is the full default `neutral` theme scaffold. Copy it into your global CSS file and adjust the tokens as needed.
::code-collapsible-wrapper
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --color-card: var(--card); --color-card-foreground: var(--card-foreground); --color-popover: var(--popover); --color-popover-foreground: var(--popover-foreground); --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-secondary: var(--secondary); --color-secondary-foreground: var(--secondary-foreground); --color-muted: var(--muted); --color-muted-foreground: var(--muted-foreground); --color-accent: var(--accent); --color-accent-foreground: var(--accent-foreground); --color-destructive: var(--destructive); --color-border: var(--border); --color-input: var(--input); --color-ring: var(--ring); --color-chart-1: var(--chart-1); --color-chart-2: var(--chart-2); --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); --radius-sm: calc(var(--radius) 0.6); --radius-md: calc(var(--radius) 0.8); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) 1.4); --radius-2xl: calc(var(--radius) 1.8); --radius-3xl: calc(var(--radius) 2.2); --radius-4xl: calc(var(--radius) 2.6); }
:root { --radius: 0.625rem; --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); --card-foreground: oklch(0.145 0 0); --popover: oklch(1 0 0); --popover-foreground: oklch(0.145 0 0); --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.97 0 0); --secondary-foreground: oklch(0.205 0 0); --muted: oklch(0.97 0 0); --muted-foreground: oklch(0.556 0 0); --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); --chart-1: oklch(0.646 0.222 41.116); --chart-2: oklch(0.6 0.118 184.704); --chart-3: oklch(0.398 0.07 227.392); --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.97 0 0); --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); }
.dark { --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0); --secondary: oklch(0.269 0 0); --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); --muted-foreground: oklch(0.708 0 0); --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); --border: oklch(1 0 0 / 10%); --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); --chart-1: oklch(0.488 0.243 264.376); --chart-2: oklch(0.696 0.17 162.48); --chart-3: oklch(0.769 0.188 70.08); --chart-4: oklch(0.627 0.265 303.9); --chart-5: oklch(0.645 0.246 16.439); --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(1 0 0 / 10%); --sidebar-ring: oklch(0.556 0 0); }
@layer base {
- {
@apply border-border outline-ring/50; }
body { @apply bg-background text-foreground; } }
::
## Without CSS Variables
If you do not want to use CSS variables, the CLI can generate components with inline Tailwind color utilities instead.
npx shadcn-vue@latest init --no-css-variables
This sets `tailwind.cssVariables` to `false` in your `components.json` file.
<div class="bg-zinc-950 text-zinc-50 dark:bg-white dark:text-zinc-950" />
<Callout class="mt-4">
This is an installation-time choice. To switch an existing project, delete and re-install your components.
</Callout>
<div class="grid sm:grid-cols-2 gap-4 sm:gap-6"> <linked-card href="/docs/dark-mode/vite"> <svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" fill="currentColor" > <title>Vite</title> <path d="m8.286 10.578.512-8.657a.306.306 0 0 1 .247-.282L17.377.006a.306.306 0 0 1 .353.385l-1.558 5.403a.306.306 0 0 0 .352.385l2.388-.46a.306.306 0 0 1 .332.438l-6.79 13.55-.123.19a.294.294 0 0 1-.252.14c-.177 0-.35-.152-.305-.369l1.095-5.301a.306.306 0 0 0-.388-.355l-1.433.435a.306.306 0 0 1-.389-.354l.69-3.375a.306.306 0 0 0-.37-.36l-2.32.536a.306.306 0 0 1-.374-.316zm14.976-7.926L17.284 3.74l-.544 1.887 2.077-.4a.8.8 0 0 1 .84.369.8.8 0 0 1 .034.783L12.9 19.93l-.013.025-.015.023-.122.19a.801.801 0 0 1-.672.37.826.826 0 0 1-.634-.302.8.8 0 0 1-.16-.67l1.029-4.981-1.12.34a.81.81 0 0 1-.86-.262.802.802 0 0 1-.165-.67l.63-3.08-2.027.468a.808.808 0 0 1-.768-.233.81.81 0 0 1-.217-.6l.389-6.57-7.44-1.33a.612.612 0 0 0-.64.906L11.58 23.691a.612.612 0 0 0 1.066-.004l11.26-20.135a.612.612 0 0 0-.644-.9z" /> </svg> <p class="mt-2 [&:not(:first-child)]:mt-2 font-medium">Vite</p> </linked-card>
<linked-card href="/docs/dark-mode/nuxt"> <svg viewBox="0 0 24 24" width="1.2em" height="1.2em" class="w-10 h-10"><path fill="currentColor" d="M13.464 19.83h8.922c.283 0 .562-.073.807-.21a1.6 1.6 0 0 0 .591-.574a1.53 1.53 0 0 0 .216-.783a1.53 1.53 0 0 0-.217-.782L17.792 7.414a1.6 1.6 0 0 0-.591-.573a1.65 1.65 0 0 0-.807-.21c-.283 0-.562.073-.807.21a1.6 1.6 0 0 0-.59.573L13.463 9.99L10.47 4.953a1.6 1.6 0 0 0-.591-.573a1.65 1.65 0 0 0-.807-.21c-.284 0-.562.073-.807.21a1.6 1.6 0 0 0-.591.573L.216 17.481a1.53 1.53 0 0 0-.217.782c0 .275.074.545.216.783a1.6 1.6 0 0 0 .59.574c.246.137.525.21.808.21h5.6c2.22 0 3.856-.946 4.982-2.79l2.733-4.593l1.464-2.457l4.395 7.382h-5.859Zm-6.341-2.46l-3.908-.002l5.858-9.842l2.923 4.921l-1.957 3.29c-.748 1.196-1.597 1.632-2.916 1.632"></path></svg> <p class="mt-2 [&:not(:first-child)]:mt-2 font-medium">Nuxt</p> </linked-card>
<linked-card href="/docs/dark-mode/vitepress"> <svg width="48" height="48" viewBox="0 0 48 48" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <path d="M5.03628 7.87818C4.75336 5.83955 6.15592 3.95466 8.16899 3.66815L33.6838 0.0367403C35.6969 -0.24977 37.5581 1.1706 37.841 3.20923L42.9637 40.1218C43.2466 42.1604 41.8441 44.0453 39.831 44.3319L14.3162 47.9633C12.3031 48.2498 10.4419 46.8294 10.159 44.7908L5.03628 7.87818Z" /> <path d="M6.85877 7.6188C6.71731 6.59948 7.41859 5.65703 8.42512 5.51378L33.9399 1.88237C34.9465 1.73911 35.8771 2.4493 36.0186 3.46861L41.1412 40.3812C41.2827 41.4005 40.5814 42.343 39.5749 42.4862L14.0601 46.1176C13.0535 46.2609 12.1229 45.5507 11.9814 44.5314L6.85877 7.6188Z" class="fill-background"/> <path d="M33.1857 14.9195L25.8505 34.1576C25.6991 34.5547 25.1763 34.63 24.9177 34.2919L12.3343 17.8339C12.0526 17.4655 12.3217 16.9339 12.7806 16.9524L22.9053 17.3607C22.9698 17.3633 23.0344 17.3541 23.0956 17.3337L32.5088 14.1992C32.9431 14.0546 33.3503 14.4878 33.1857 14.9195Z" /> <path d="M27.0251 12.5756L19.9352 15.0427C19.8187 15.0832 19.7444 15.1986 19.7546 15.3231L20.3916 23.063C20.4066 23.2453 20.5904 23.3628 20.7588 23.2977L22.7226 22.5392C22.9064 22.4682 23.1021 22.6138 23.0905 22.8128L22.9102 25.8903C22.8982 26.0974 23.1093 26.2436 23.295 26.1567L24.4948 25.5953C24.6808 25.5084 24.892 25.6549 24.8795 25.8624L24.5855 30.6979C24.5671 31.0004 24.9759 31.1067 25.1013 30.8321L25.185 30.6487L29.4298 17.8014C29.5008 17.5863 29.2968 17.3809 29.0847 17.454L27.0519 18.1547C26.8609 18.2205 26.6675 18.0586 26.6954 17.8561L27.3823 12.8739C27.4103 12.6712 27.2163 12.5091 27.0251 12.5756Z" class="stroke-background"/> </svg> <p class="mt-2 [&:not(:first-child)]:mt-2 font-medium">Vitepress</p> </linked-card>
<linked-card href="/docs/dark-mode/astro"> <svg role="img" viewBox="0 0 64 79" xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" fill="currentColor" > <path d="M19.9924 65.9282C16.1165 62.432 14.9851 55.0859 16.5999 49.7638C19.3998 53.1193 23.2793 54.1822 27.2977 54.7822C33.5013 55.7081 39.5937 55.3618 45.3565 52.5637C46.0158 52.2434 46.625 51.8174 47.3454 51.386C47.8861 52.9341 48.0268 54.497 47.838 56.0877C47.3787 59.9617 45.4251 62.9542 42.3177 65.2227C41.0752 66.13 39.7604 66.9411 38.4771 67.7967C34.5346 70.4262 33.4679 73.5095 34.9494 77.9946C34.9846 78.1038 35.0161 78.2131 35.0957 78.4797C33.0828 77.5909 31.6124 76.2965 30.4921 74.5946C29.3088 72.7984 28.7458 70.8114 28.7162 68.6615C28.7014 67.6152 28.7014 66.5597 28.5588 65.5282C28.2107 63.0135 27.0144 61.8876 24.7608 61.8227C22.4479 61.7561 20.6183 63.1672 20.1331 65.3893C20.0961 65.5597 20.0424 65.7282 19.9887 65.9263L19.9924 65.9282Z" /> <path d="M0.5 51.3932C0.5 51.3932 11.0979 46.2433 21.7254 46.2433L29.7382 21.5069C30.0381 20.3106 30.9141 19.4977 31.9029 19.4977C32.8918 19.4977 33.7677 20.3106 34.0677 21.5069L42.0804 46.2433C54.6672 46.2433 63.3058 51.3932 63.3058 51.3932C63.3058 51.3932 45.3044 2.47586 45.2692 2.37772C44.7526 0.931458 43.8804 0 42.7045 0H21.1032C19.9273 0 19.0903 0.931458 18.5384 2.37772C18.4995 2.47401 0.5 51.3932 0.5 51.3932Z" /> </svg> <p class="mt-2 [&:not(:first-child)]:mt-2 font-medium">Astro</p> </linked-card> </div>
init
Use the init command to initialize configuration and dependencies for a new project.
The init command installs dependencies, adds the cn util and configures CSS variables for the project.
npx shadcn-vue@latest initOptions
Usage: shadcn-vue init [options] [components...]
initialize your project and install dependencies
Arguments:
components names, url or local path to component
Options:
-p, --preset <preset> use a preset configuration or URL. (reka-vega, reka-nova, reka-maia, reka-lyra, reka-mira, reka-luma)
-t, --template <template> the template to use. (nuxt, vite, astro, laravel)
--base <base> the component library base to use. (reka)
--style <style> the visual style to use. (vega, nova, maia, lyra, mira)
--icon-library <icon-library> the icon library to use. (lucide, tabler, hugeicons, phosphor, remixicon)
--font <font> the font to use. (inter, figtree, jetbrains-mono, geist, geist-mono)
-b, --base-color <base-color> the base color to use. (neutral, gray, zinc, stone, slate)
-n, --name <name> the name for the new project.
-d, --defaults use default configuration. (default: false)
-y, --yes skip confirmation prompt. (default: true)
-f, --force force overwrite of existing configuration. (default: false)
-c, --cwd <cwd> the working directory. defaults to the current directory.
-s, --silent mute output. (default: false)
--src-dir use the src directory when creating a new project. (default: false)
--no-src-dir do not use the src directory when creating a new project.
--reinstall re-install existing UI components.
--no-reinstall do not re-install existing UI components.
--rtl enable RTL support.
--no-rtl disable RTL support.
--css-variables use css variables for theming. (default: true)
--no-css-variables do not use css variables for theming.
--no-base-style do not install the base shadcn style.
-h, --help display help for commandThe create command is an alias for init:
npx shadcn-vue@latest create---
add
Use the add command to add components and dependencies to your project.
npx shadcn-vue@latest add [component]Options
Usage: shadcn-vue add [options] [components...]
add a component to your project
Arguments:
components names, url or local path to component
Options:
-y, --yes skip confirmation prompt. (default: false)
-o, --overwrite overwrite existing files. (default: false)
-c, --cwd <cwd> the working directory. defaults to the current directory.
-a, --all add all available components (default: false)
-p, --path <path> the path to add the component to.
-s, --silent mute output. (default: false)
--dry-run preview changes without writing files. (default: false)
--diff [path] show diff for a file.
--view [path] show file contents.
-h, --help display help for command---
apply
Use the apply command to apply a preset to an existing project.
npx shadcn-vue@latest apply --preset novaOptions
Usage: shadcn-vue apply [options] [preset]
apply a preset to an existing project
Arguments:
preset the preset to apply
Options:
--preset <preset> preset configuration to apply
-y, --yes skip confirmation prompt. (default: false)
-c, --cwd <cwd> the working directory. defaults to the current directory.
-s, --silent mute output. (default: false)
-h, --help display help for command---
view
Use the view command to view items from the registry before installing them.
npx shadcn-vue@latest view [item]You can view multiple items at once:
npx shadcn-vue@latest view button card dialogOr view items from namespaced registries:
npx shadcn-vue@latest view @acme/auth @v0/dashboardOptions
Usage: shadcn-vue view [options] <items...>
view items from the registry
Arguments:
items the item names or URLs to view
Options:
-c, --cwd <cwd> the working directory. defaults to the current directory.
-h, --help display help for command---
search
Use the search command to search for items from registries.
npx shadcn-vue@latest search [registry]You can search with a query:
npx shadcn-vue@latest search @shadcn-vue -q "button"Or search multiple registries at once:
npx shadcn-vue@latest search @shadcn-vue @v0 @acmeThe list command is an alias for search:
npx shadcn-vue@latest list @acmeOptions
Usage: shadcn-vue search|list [options] <registries...>
search items from registries
Arguments:
registries the registry names or urls to search items from. Names
must be prefixed with @.
Options:
-c, --cwd <cwd> the working directory. defaults to the current directory.
-q, --query <query> query string
-l, --limit <number> maximum number of items to display per registry (default: "100")
-o, --offset <number> number of items to skip (default: "0")
-h, --help display help for command---
build
Use the build command to generate the registry JSON files.
npx shadcn-vue@latest buildThis command reads the registry.json file and generates the registry JSON files in the public/r directory.
Options
Usage: shadcn-vue build [options] [registry]
build components for a shadcn-vue registry
Arguments:
registry path to registry.json file (default: "./registry.json")
Options:
-o, --output <path> destination directory for json files (default: "./public/r")
-c, --cwd <cwd> the working directory. defaults to the current directory.
-h, --help display help for commandTo customize the output directory, use the --output option.
npx shadcn-vue@latest build --output ./public/registry---
docs
Use the docs command to fetch documentation and API references for components.
npx shadcn-vue@latest docs [component]Options
Usage: shadcn-vue docs [options] <components...>
get docs, api references and usage examples for components
Arguments:
components component names
Options:
-c, --cwd <cwd> the working directory. defaults to the current directory.
-b, --base <base> the base to use (reka). defaults to project base.
--json output as JSON. (default: false)
-h, --help display help for command---
info
Use the info command to get information about your project.
npx shadcn-vue@latest infoOptions
Usage: shadcn-vue info [options]
get information about your project
Options:
-c, --cwd <cwd> the working directory. defaults to the current directory.
--json output as JSON. (default: false)
-h, --help display help for command---
migrate
Use the migrate command to run migrations on your project.
npx shadcn-vue@latest migrate [migration]Available Migrations
| Migration | Description |
|---|---|
icons | Migrate your UI components to a different icon library. |
rtl | Migrate your components to support RTL (right-to-left). |
Options
Usage: shadcn-vue migrate [options] [migration] [path]
run a migration.
Arguments:
migration the migration to run.
path optional path or glob pattern to migrate.
Options:
-c, --cwd <cwd> the working directory. defaults to the current directory.
-l, --list list all migrations. (default: false)
-y, --yes skip confirmation prompt. (default: false)
-h, --help display help for command---
migrate rtl
The rtl migration transforms your components to support RTL (right-to-left) languages.
npx shadcn-vue@latest migrate rtlThis will:
1. Update components.json to set rtl: true 2. Transform physical CSS properties to logical equivalents (e.g., ml-4 → ms-4, text-left → text-start) 3. Add rtl: variants where needed (e.g., space-x-4 → space-x-4 rtl:space-x-reverse)
Migrate specific files
You can migrate specific files or use glob patterns:
# Migrate a specific file
npx shadcn-vue@latest migrate rtl src/components/ui/button/Button.vue
# Migrate files matching a glob pattern
npx shadcn-vue@latest migrate rtl "src/components/ui/**"If no path is provided, the migration will transform all files in your ui directory (from components.json).
This project and the components are written in TypeScript. We recommend using TypeScript for your project as well.
However we provide a JavaScript version of the components as well. The JavaScript version is available via the cli.
To opt-out of TypeScript, you can use the typescript flag in your components.json file.
```json {9} title="components.json" showLineNumbers { "style": "default", "tailwind": { "config": "tailwind.config.js", "css": "src/app/globals.css", "baseColor": "zinc", "cssVariables": true }, "typescript": false, "aliases": { "utils": "~/lib/utils", "components": "~/components" } }
To configure import aliases, you can use the following `jsconfig.json`:
{ "compilerOptions": { "paths": { "@/": ["./"] } } }
<Callout>
Note: The Figma files are contributed by the community. If you have any questions or feedback, please reach out to the Figma file maintainers.
</Callout>
Paid
- shadcn/ui kit by Matt Wierzbicki - A premium, always up-to-date UI kit for Figma - shadcn/ui compatible and optimized for smooth design-to-dev handoff.
Free
- shadcn/ui design system by Pietro Schirano - A design companion for shadcn/ui. Each component was painstakingly crafted to perfectly match the code implementation.
- Obra shadcn/ui by Obra Studio - Carefully crafted kit designed in the philosophy of shadcn, tracks v4, MIT licensed
You're looking at the docs for shadcn-vue + Tailwind v4. If you're looking for the docs for shadcn/ui + Tailwind v3, you can find them here.
<button-a to="https://v3.shadcn-vue.com" target="_blank"> View the legacy docs </button-a>
::component-preview --- name: AccordionDemo class: '[&_.preview>div]:sm:max-w-[80%] **:[.preview]:min-h-[400px]' description: An accordion with three items align: start --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add accordion::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from '@/components/ui/accordion' </script>
<template> <Accordion type="single" collapsible> <AccordionItem value="item-1"> <AccordionTrigger>Is it accessible?</AccordionTrigger> <AccordionContent> Yes. It adheres to the WAI-ARIA design pattern. </AccordionContent> </AccordionItem> </Accordion> </template>
::component-preview --- name: AlertDialogDemo class: '[&_.preview]:min-h-[400px]' description: An alert dialog that asks for user confirmation --- ::
::vue-school-link{class="mt-6" lesson="dialogs-and-alerts-with-shadcn-vue" placement="top"} Watch a Vue School video about dialogs and alerts in shadcn-vue. ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add alert-dialog::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog' </script>
<template> <AlertDialog> <AlertDialogTrigger>Open</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle> <AlertDialogDescription> This action cannot be undone. This will permanently delete your account and remove your data from our servers. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction>Continue</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> </template>
::component-preview --- name: AlertDemo title: An alert with an icon, title and description. description: An alert with an icon, title and description. --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add alert::
::tabs-content{value="manual"} ::steps ::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' </script>
<template> <Alert> <AlertTitle>Heads up!</AlertTitle> <AlertDescription> You can add components and dependencies to your app using the cli. </AlertDescription> </Alert> </template>
::component-preview --- name: AspectRatioDemo description: A component that displays an image with a 16:9 aspect ratio. --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add aspect-ratio::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script lang="ts"> import { AspectRatio } from '@/components/ui/aspect-ratio' </script>
<template> <AspectRatio :ratio="16 / 9"> <img src="..." alt="Image" class="rounded-md object-cover"> </AspectRatio> </template>
::component-preview --- name: AvatarDemo class: '[&_.preview]:min-h-[200px]' description: An avatar with a fallback. --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add avatar::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' </script>
<template> <Avatar> <AvatarImage src="https://github.com/shadcn.png" /> <AvatarFallback>CN</AvatarFallback> </Avatar> </template>
::component-preview --- name: BadgeDemo description: A default badge --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add badge::
::tabs-content{value="manual"} ::steps ::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Badge } from '@/components/ui/badge' </script>
<template> <Badge variant="default | outline | secondary | destructive"> Badge </Badge> </template>
### Link
You can use the `as-child` prop to make another component look like a badge. Here's an example of a link that looks like a badge.
<script setup lang="ts"> import { Badge } from '@/components/ui/badge' </script>
<template> <Badge as-child> <a href="#">Badge</a> </Badge> </template>
::component-preview --- name: BreadcrumbDemo class: '[&_.preview]:p-2' description: A breadcrumb with a collapsible dropdown. --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add breadcrumb::
::tabs-content{value="manual"} ::steps ::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, } from '@/components/ui/breadcrumb' </script>
<template> <Breadcrumb> <BreadcrumbList> <BreadcrumbItem> <BreadcrumbLink href="/"> Home </BreadcrumbLink> </BreadcrumbItem> <BreadcrumbSeparator /> <BreadcrumbItem> <BreadcrumbLink href="/components"> Components </BreadcrumbLink> </BreadcrumbItem> <BreadcrumbSeparator /> <BreadcrumbItem> <BreadcrumbPage>Breadcrumb</BreadcrumbPage> </BreadcrumbItem> </BreadcrumbList> </Breadcrumb> </template>
## Examples
### Custom separator
Use a custom component as `children` for `<BreadcrumbSeparator />` to create a custom separator.
::component-preview
---
name: BreadcrumbCustomSeparatorDemo
---
::
<script setup lang="ts"> import { SlashIcon } from 'lucide-vue-next' // ... </script>
<template> <Breadcrumb> <BreadcrumbList> <BreadcrumbItem> <BreadcrumbLink href="/"> Home </BreadcrumbLink> </BreadcrumbItem> <BreadcrumbSeparator> <SlashIcon /> </BreadcrumbSeparator> <BreadcrumbItem> <BreadcrumbLink href="/components"> Components </BreadcrumbLink> </BreadcrumbItem> </BreadcrumbList> </Breadcrumb> </template>
----
### Dropdown
You can compose `<BreadcrumbItem />` with a `<DropdownMenu />` to create a dropdown in the breadcrumb.
::component-preview
---
name: BreadcrumbDropdownDemo
---
::
<script setup lang="ts"> import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" //... </script>
<template> <BreadcrumbItem> <DropdownMenu> <DropdownMenuTrigger> Components </DropdownMenuTrigger> <DropdownMenuContent align="start"> <DropdownMenuItem>Documentation</DropdownMenuItem> <DropdownMenuItem>Themes</DropdownMenuItem> <DropdownMenuItem>GitHub</DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> </BreadcrumbItem> </template>
----
### Collapsed
We provide a `<BreadcrumbEllipsis />` component to show a collapsed state when the breadcrumb is too long.
::component-preview
---
name: BreadcrumbCollapsedDemo
---
::
<script setup lang="ts"> import { BreadcrumbEllipsis } from "@/components/ui/breadcrumb" //... </script>
<template> <Breadcrumb> <BreadcrumbList> <!-- ... --> <BreadcrumbItem> <BreadcrumbEllipsis /> </BreadcrumbItem> <!-- ... --> </BreadcrumbList> </Breadcrumb> </template>
----
### Link component
To use a custom link component from your routing library, you can use the `as-child` prop on `<BreadcrumbLink />`.
::component-preview
---
name: BreadcrumbLinkDemo
---
::
<script setup lang="ts"> import { NuxtLink } from '#components' // ... </script>
<template> <Breadcrumb> <BreadcrumbList> <BreadcrumbItem> <BreadcrumbLink as-child> <NuxtLink to="/"> Home </NuxtLink> </BreadcrumbLink> </BreadcrumbItem> {/ ... /} </BreadcrumbList> </Breadcrumb> </template>
----
### Responsive
Here's an example of a responsive breadcrumb that composes `<BreadcrumbItem />` with `<BreadcrumbEllipsis />`, ` <DropdownMenu />`, and `<Drawer />`.
It displays a dropdown on desktop and a drawer on mobile.
::component-preview
---
name: BreadcrumbResponsiveDemo
---
::
::component-preview --- name: ButtonGroupDemo class: '[&_.preview]:min-h-[400px]' --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add button-group::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
<script setup lang="ts">
import {
ButtonGroup,
ButtonGroupSeparator,
ButtonGroupText,
} from '@/components/ui/button-group'
</script>
<template>
<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
</template>Accessibility
- The
ButtonGroupcomponent has theroleattribute set togroup. - Use
Tabto navigate between the buttons in the group. - Use
aria-labeloraria-labelledbyto label the button group.
<template>
<ButtonGroup aria-label="Button group">
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
</template>ButtonGroup vs ToggleGroup
- Use the
ButtonGroupcomponent when you want to group buttons that perform an action. - Use the
ToggleGroupcomponent when you want to group buttons that toggle a state.
Examples
Orientation
Set the orientation prop to change the button group layout.
::component-preview --- name: ButtonGroupOrientationDemo --- ::
Size
Control the size of buttons using the size prop on individual buttons.
::component-preview --- name: ButtonGroupSizeDemo --- ::
Nested
<ButtonGroup> components to create button groups with spacing.
::component-preview --- name: ButtonGroupNestedDemo --- ::
Separator
The ButtonGroupSeparator component visually divides buttons within a group.
Buttons with variant outline do not need a separator since they have a border. For other variants, a separator is recommended to improve the visual hierarchy.
::component-preview --- name: ButtonGroupSeparatorDemo --- ::
Split
Create a split button group by adding two buttons separated by a ButtonGroupSeparator.
::component-preview --- name: ButtonGroupSplitDemo --- ::
Input
Wrap an Input component with buttons.
::component-preview --- name: ButtonGroupWithInputDemo --- ::
Input Group
Wrap an InputGroup component to create complex input layouts.
::component-preview --- name: ButtonGroupInputGroupDemo --- ::
Dropdown Menu
Create a split button group with a DropdownMenu component.
::component-preview --- name: ButtonGroupWithDropdownMenuDemo --- ::
Select
Pair with a Select component.
::component-preview --- name: ButtonGroupWithSelectDemo --- ::
Popover
Use with a Popover component.
::component-preview --- name: ButtonGroupWithPopoverDemo --- ::
API Reference
ButtonGroup
The ButtonGroup component is a container that groups related buttons together with consistent styling.
| Prop | Type | Default |
|---|---|---|
orientation | "horizontal" \ | "vertical" |
<template>
<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
</template>Nest multiple button groups to create complex layouts with spacing. See the nested example for more details.
<template>
<ButtonGroup>
<ButtonGroup />
<ButtonGroup />
</ButtonGroup>
</template>ButtonGroupSeparator
The ButtonGroupSeparator component visually divides buttons within a group.
| Prop | Type | Default |
|---|---|---|
orientation | `"horizontal" \ | "vertical"` |
<template>
<ButtonGroup>
<Button>Button 1</Button>
<ButtonGroupSeparator />
<Button>Button 2</Button>
</ButtonGroup>
</template>ButtonGroupText
Use this component to display text within a button group.
| Prop | Type | Default |
|---|---|---|
as-child | boolean | false |
<template>
<ButtonGroup>
<ButtonGroupText>Text</ButtonGroupText>
<Button>Button</Button>
</ButtonGroup>
</template>Use the as-child prop to render a custom component as the text, for example a label.
<script setup lang="ts">
import { ButtonGroupText } from '@/components/ui/button-group'
import { Label } from '@/components/ui/label'
</script>
<template>
<ButtonGroup>
<ButtonGroupText as-child>
<Label for="name">Text</Label>
</ButtonGroupText>
<Input id="name" placeholder="Type something here..." />
</ButtonGroup>
</template>::component-preview --- name: ButtonDemo description: A button --- ::
::vue-school-link{class="mt-6" lesson="buttons-variants-and-the-as-child-prop-with-shadcn-vue" placement="top"} Watch a Vue School video about buttons, variants, and the as-child prop in shadcn-vue. ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add button::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Button } from '@/components/ui/button' </script>
<template> <Button variant="outline"> Button </Button> </template>
## Cursor
Tailwind v4 switched from `cursor: pointer` to `cursor: default` for the button component.
If you want to keep the `cursor: pointer` behavior, add the following code to your CSS file:
@layer base { button:not(:disabled), [role="button"]:not(:disabled) { cursor: pointer; } }
## Examples
### Size
::component-preview
---
name: ButtonSize
class: mb-4
---
::
### Default
::component-preview
---
name: ButtonDefault
class: mb-4
---
::
### Outline
::component-preview
---
name: ButtonOutline
class: mb-4
---
::
### Secondary
::component-preview
---
name: ButtonSecondary
class: mb-4
---
::
### Ghost
::component-preview
---
name: ButtonGhost
class: mb-4
---
::
### Destructive
::component-preview
---
name: ButtonDestructive
class: mb-4
---
::
### Link
::component-preview
---
name: ButtonLink
class: mb-4
---
::
### Icon
::component-preview
---
name: ButtonIcon
class: mb-4
---
::
<template> <Button variant="outline" size="icon" aria-label="Submit"> <CircleFadingArrowUpIcon /> </Button> </template>
### With Icon
The spacing between the icon and the text is automatically adjusted based on the size of the button. You do not need any margin on the icon.
::component-preview
---
name: ButtonWithIcon
class: mb-4
---
::
### Rounded
Use the `rounded-full` class to make the button rounded.
::component-preview
---
name: ButtonRounded
class: mb-4
---
::
### Spinner
::component-preview
---
name: ButtonLoading
class: mb-4
---
::
### Button Group
::component-preview
---
name: ButtonGroupDemo
class: mb-4
---
::
To create a button group, use the `ButtonGroup` component. See the [Button Group](/docs/components/button-group) documentation for more details.
### Link (asChild)
You can use the `as-child` prop to make another component look like a button. Here's an example of a link that looks like a button.
<script setup lang="ts"> import { Button } from '@/components/ui/button' </script>
<template> <Button as-child> <a href="/login">Login</a> </Button> </template>
## API Reference
### Button
The `Button` component is a wrapper around the `button` element that adds a variety of styles and functionality.
| Prop | Type | Default |
| --------- | ----------------------------------------------------------------------------- | ----------- |
| `variant` | `"default" \| "outline" \| "ghost" \| "destructive" \| "secondary" \| "link"` | `"default"` |
| `size` | `"default" \| "sm" \| "lg" \| "icon" \| "icon-sm" \| "icon-lg"` | `"default"` |
| `asChild` | `boolean` | `false` |
::component-preview --- name: CardDemo description: A card with a form --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add card::
::tabs-content{value="manual"} ::steps ::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, } from '@/components/ui/card' </script>
<template> <Card> <CardHeader> <CardTitle>Card Title</CardTitle> <CardDescription>Card Description</CardDescription> </CardHeader> <CardContent> <p>Card Content</p> </CardContent> <CardFooter> <p>Card Footer</p> </CardFooter> </Card> </template>
::component-preview --- name: CheckboxDemo description: A checkbox --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add checkbox::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Checkbox } from '@/components/ui/checkbox' </script>
<template> <Checkbox /> </template>
::component-preview --- name: CollapsibleDemo description: A collapsible component. --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add collapsible::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible' </script>
<template> <Collapsible> <CollapsibleTrigger>Can I use this in my project?</CollapsibleTrigger> <CollapsibleContent> Yes. Free to use for personal and commercial projects. No attribution required. </CollapsibleContent> </Collapsible> </template>
::component-preview --- name: CommandDemo description: A command component. class: "[&_.preview>div]:max-w-[450px]" --- ::
Installation
::code-tabs
::tabs-list
::tabs-trigger{value="cli"} CLI ::
::tabs-trigger{value="manual"} Manual ::
::
::tabs-content{value="cli"}
npx shadcn-vue@latest add command::
::tabs-content{value="manual"} ::steps ::step Install the following dependencies: ::
npm install reka-ui::step Copy and paste the GitHub source code into your project. ::
::step Update the import paths to match your project setup. :: :: ::
::
Usage
```vue showLineNumbers <script setup lang="ts"> import { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, } from '@/components/ui/command' </script>
<template> <Command> <CommandInput placeholder="Type a command or search..." /> <CommandList> <CommandEmpty>No results found.</CommandEmpty> <CommandGroup heading="Suggestions"> <CommandItem>Calendar</CommandItem> <CommandItem>Search Emoji</CommandItem> <CommandItem>Calculator</CommandItem> </CommandGroup> <CommandSeparator /> <CommandGroup heading="Settings"> <CommandItem>Profile</CommandItem> <CommandItem>Billing</CommandItem> <CommandItem>Settings</CommandItem> </CommandGroup> </CommandList> </Command> </template>