mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 20:19:34 +01:00
226 lines
6.5 KiB
Markdown
226 lines
6.5 KiB
Markdown
---
|
|
description: 'Learn how to customize the appearance of Nuxt UI components using Tailwind CSS.'
|
|
---
|
|
|
|
## Tailwind CSS
|
|
|
|
Since Nuxt UI v3 uses Tailwind CSS v4 alpha which doesn't have a documentation yet, let's have a look on how to use it.
|
|
|
|
Tailwind CSS v4 takes a CSS-first configuration approach, you now customize your theme with CSS variables inside a `@theme` directive:
|
|
|
|
```css [main.css]
|
|
@import "tailwindcss";
|
|
@import "@nuxt/ui";
|
|
|
|
@theme {
|
|
--font-family-display: "Inter", "sans-serif";
|
|
|
|
--breakpoint-3xl: 1920px;
|
|
|
|
--color-green-50: #EFFDF5;
|
|
--color-green-100: #D9FBE8;
|
|
--color-green-200: #B3F5D1;
|
|
--color-green-300: #75EDAE;
|
|
--color-green-400: #00DC82;
|
|
--color-green-500: #00C16A;
|
|
--color-green-600: #00A155;
|
|
--color-green-700: #007F45;
|
|
--color-green-800: #016538;
|
|
--color-green-900: #0A5331;
|
|
--color-green-950: #052E16;
|
|
}
|
|
```
|
|
|
|
The `@theme` directive tells Tailwind to make new utilities and variants available based on those variables. It's the equivalent of the `theme.extend` key in Tailwind CSS v3 `tailwind.config.ts` file.
|
|
|
|
::note
|
|
You can learn more about this on [https://tailwindcss.com/blog/tailwindcss-v4-alpha](https://tailwindcss.com/blog/tailwindcss-v4-alpha#css-first-configuration).
|
|
::
|
|
|
|
This is exactly what the [`@import "@nuxt/ui";`](https://github.com/nuxt/ui/blob/v3/src/runtime/index.css) is all about, it extends the default Tailwind CSS theme and declares the `primary`, `error` and `gray` colors to be configurable through the [App Config](https://nuxt.com/docs/guide/directory-structure/app-config#app-config-file) but we'll talk more about that in the [Colors](/getting-started/colors) section.
|
|
|
|
## Tailwind Variants API
|
|
|
|
Nuxt UI components are styled using the [Tailwind Variants](https://www.tailwind-variants.org/) API, which provides a powerful way to create variants and manage component styles. Let's explore the key features of this API:
|
|
|
|
### Slots
|
|
|
|
Components in Nuxt UI can have multiple `slots`, each representing a distinct HTML element or section within the component. These slots allow for flexible content insertion and styling. Let's take the [Card](/components/card) component as an example:
|
|
|
|
::code-group
|
|
|
|
```ts [src/theme/card.ts]
|
|
export default {
|
|
slots: {
|
|
root: 'bg-white dark:bg-gray-900 ring ring-gray-200 dark:ring-gray-800 divide-y divide-gray-200 dark:divide-gray-800 rounded-lg shadow',
|
|
header: 'p-4 sm:px-6',
|
|
body: 'p-4 sm:p-6',
|
|
footer: 'p-4 sm:px-6'
|
|
}
|
|
}
|
|
```
|
|
|
|
```vue [src/runtime/components/Card.vue]
|
|
<template>
|
|
<div :class="ui.root({ class: [props.class, props.ui?.root] })">
|
|
<div :class="ui.header({ class: props.ui?.header })">
|
|
<slot name="header" />
|
|
</div>
|
|
|
|
<div :class="ui.body({ class: props.ui?.body })">
|
|
<slot />
|
|
</div>
|
|
|
|
<div :class="ui.footer({ class: props.ui?.footer })">
|
|
<slot name="footer" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
::
|
|
|
|
Some components don't have slots, they are just composed of a single root element. In this case, the theme only defines the `base` slot like the [Container](/components/container) component for example:
|
|
|
|
::code-group
|
|
|
|
```ts [src/theme/container.ts]
|
|
export default {
|
|
base: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8'
|
|
}
|
|
```
|
|
|
|
```vue [src/runtime/components/Container.vue]
|
|
<template>
|
|
<div :class="container({ class: props.class })">
|
|
<slot />
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
::
|
|
|
|
::caution
|
|
Components without slots don't have a [`ui` prop](#ui-prop), only the [`class` prop](#class-prop) is available to override styles.
|
|
::
|
|
|
|
### Variants
|
|
|
|
Nuxt UI components use `variants` to change the `slots` styles based on props. Here's an example of the [Avatar](/components/avatar) component:
|
|
|
|
```ts [src/theme/avatar.ts]
|
|
export default {
|
|
slots: {
|
|
root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-gray-100 dark:bg-gray-800',
|
|
image: 'h-full w-full rounded-[inherit] object-cover'
|
|
},
|
|
variants: {
|
|
size: {
|
|
'sm': {
|
|
root: 'size-7 text-sm'
|
|
},
|
|
'md': {
|
|
root: 'size-8 text-base'
|
|
},
|
|
'lg': {
|
|
root: 'size-9 text-lg'
|
|
}
|
|
}
|
|
},
|
|
defaultVariants: {
|
|
size: 'md'
|
|
}
|
|
}
|
|
```
|
|
|
|
This way, the `size` prop will apply the corresponding styles to the `root` slot:
|
|
|
|
::component-code{slug="avatar"}
|
|
---
|
|
ignore:
|
|
- src
|
|
props:
|
|
src: 'https://github.com/benjamincanac.png'
|
|
size: lg
|
|
---
|
|
::
|
|
|
|
The `defaultVariants` property specifies the default values for each variant. It determines how a component looks and behaves when no prop is provided. These default values can be customized in your [`app.config.ts`](#appconfigts) to adjust the standard appearance of components throughout your application.
|
|
|
|
## Customize components
|
|
|
|
You have multiple ways to customize the appearance of Nuxt UI components, you can do it for all components at once or on a per-component basis.
|
|
|
|
::tip
|
|
Tailwind Variants uses [tailwind-merge](https://github.com/dcastil/tailwind-merge) under the hood to merge classes so you don't have to worry about conflicting classes.
|
|
::
|
|
|
|
::note
|
|
You can explore the theme for each component in two ways:
|
|
|
|
- Check the `Theme` section in the documentation of each individual component.
|
|
- Browse the source code directly in the GitHub repository at https://github.com/nuxt/ui/tree/v3/src/theme.
|
|
::
|
|
|
|
### `app.config.ts`
|
|
|
|
You can override the theme of components inside your `app.config.ts` by using the exact same structure as the theme object.
|
|
|
|
Let's say you want to change the font weight of all your buttons, you can do it like this:
|
|
|
|
```ts [app.config.ts]
|
|
export default defineAppConfig({
|
|
ui: {
|
|
button: {
|
|
slots: {
|
|
base: 'font-bold'
|
|
}
|
|
}
|
|
}
|
|
})
|
|
```
|
|
|
|
In this example, the `font-bold` class will override the default `font-medium` class on all buttons.
|
|
|
|
### `ui` prop
|
|
|
|
You can also override a component's **slots** using the `ui` prop. This has priority over the `app.config.ts` configuration and `variants` resolution.
|
|
|
|
::component-code{slug="button"}
|
|
---
|
|
prettier: true
|
|
ignore:
|
|
- ui.leadingIcon
|
|
- color
|
|
- variant
|
|
- size
|
|
- icon
|
|
props:
|
|
icon: i-heroicons-magnifying-glass
|
|
size: md
|
|
color: gray
|
|
variant: outline
|
|
ui:
|
|
leadingIcon: 'text-primary-500 dark:text-primary-400 size-3'
|
|
slots:
|
|
default: |
|
|
|
|
Button
|
|
---
|
|
::
|
|
|
|
In this example, the `leadingIcon` slot is overwritten even though the `md` size variant would apply a `size-5` class by default.
|
|
|
|
### `class` prop
|
|
|
|
The `class` prop allows you to override the classes of the `root` or `base` slot. This has priority over the `app.config.ts` configuration and `variants` resolution.
|
|
|
|
::component-code{slug="button"}
|
|
---
|
|
props:
|
|
class: 'font-bold rounded-full'
|
|
slots:
|
|
default: Button
|
|
---
|
|
::
|