mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-29 11:20:36 +01:00
docs: migrate to nuxt compatibility 4
This commit is contained in:
@@ -1,470 +0,0 @@
|
||||
---
|
||||
description: 'Learn how to customize the look and feel of the components.'
|
||||
---
|
||||
|
||||
This module relies on Nuxt [App Config](https://nuxt.com/docs/guide/directory-structure/app-config#app-config-file) file to customize the look and feel of the components at runtime with HMR (hot-module-replacement).
|
||||
|
||||
## Colors
|
||||
|
||||
### Configuration
|
||||
|
||||
Components are based on a `primary` and a `gray` color. You can change them in your `app.config.ts`.
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
primary: 'green',
|
||||
gray: 'cool'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Try to change the `primary` and `gray` colors by clicking on the :u-icon{name="i-heroicons-swatch-20-solid" class="w-4 h-4 align-middle text-primary-500 dark:text-primary-400"} button in the header.
|
||||
::
|
||||
|
||||
As this module uses Tailwind CSS under the hood, you can use any of the [Tailwind CSS colors](https://tailwindcss.com/docs/customizing-colors#color-palette-reference) or your own custom colors. By default, the `primary` color is `green` and the `gray` color is `cool`.
|
||||
|
||||
When [using custom colors](https://tailwindcss.com/docs/customizing-colors#using-custom-colors) or [adding additional colors](https://tailwindcss.com/docs/customizing-colors#adding-additional-colors) through the `extend` key in your `tailwind.config.ts`, you'll need to make sure to define all the shades from `50` to `950` as most of them are used in the components config defined in [`ui.config/`](https://github.com/nuxt/ui/tree/dev/src/runtime/ui.config) directory. You can [generate your colors](https://tailwindcss.com/docs/customizing-colors#generating-colors) using tools such as https://uicolors.app/ for example.
|
||||
|
||||
```ts [tailwind.config.ts]
|
||||
import type { Config } from 'tailwindcss'
|
||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||
|
||||
export default <Partial<Config>>{
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
green: {
|
||||
50: '#EFFDF5',
|
||||
100: '#D9FBE8',
|
||||
200: '#B3F5D1',
|
||||
300: '#75EDAE',
|
||||
400: '#00DC82',
|
||||
500: '#00C16A',
|
||||
600: '#00A155',
|
||||
700: '#007F45',
|
||||
800: '#016538',
|
||||
900: '#0A5331',
|
||||
950: '#052e16'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### CSS Variables
|
||||
|
||||
To provide dynamic colors that can be changed at runtime, this module uses CSS variables. As Tailwind CSS already has a `gray` color, the module automatically renames it to `cool` to avoid conflicts (`coolGray` was renamed to `gray` when Tailwind CSS v3.0 was released).
|
||||
|
||||
Likewise, you can't define a `primary` color in your `tailwind.config.ts` as it would conflict with the `primary` color defined by the module.
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
We'd advise you to use those colors in your components and pages, e.g. `text-primary-500 dark:text-primary-400`, `bg-gray-100 dark:bg-gray-900`, etc. so your app automatically adapts when changing your `app.config.ts`.
|
||||
::
|
||||
|
||||
The `primary` color also has a `DEFAULT` shade that changes based on the theme. It is `500` in light mode and `400` in dark mode. You can use as a shortcut in your components and pages, e.g. `text-primary`, `bg-primary`, `focus-visible:ring-primary`, etc.
|
||||
|
||||
### Smart Safelisting
|
||||
|
||||
Components having a `color` prop like [Avatar](/components/avatar#chip), [Badge](/components/badge#style), [Button](/components/button#style), [Input](/components/input#style) (inherited in [Select](/components/select) and [SelectMenu](/components/select-menu)), [RadioGroup](/components/radio-group), [Checkbox](/components/checkbox), [Toggle](/components/toggle), [Range](/components/range) and [Notification](/components/notification#timeout) will use the `primary` color by default but will handle all the colors defined in your `tailwind.config.ts` or the default Tailwind CSS colors.
|
||||
|
||||
Variant classes of those components are defined with a syntax like `bg-{color}-500 dark:bg-{color}-400` so they can be used with any color. However, this means that Tailwind will not find those classes and therefore will not generate the corresponding CSS.
|
||||
|
||||
The module uses the [Tailwind CSS safelist](https://tailwindcss.com/docs/content-configuration#safelisting-classes) feature to force the generation of all the classes for the `primary` color **only** as it is the default color for all the components.
|
||||
|
||||
Then, the module will automatically detect when you use one of those components with a color and will safelist it for you. This means that if you use a `red` color for a Button component, the `red` color classes will be safelisted for the Button component only. This will allow to keep the CSS bundle size as small as possible.
|
||||
|
||||
There is one case where you would want to force the safelisting of a color. For example, if you've set the default color of the Button component to `orange` in your `app.config.ts`.
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
button: {
|
||||
default: {
|
||||
color: 'orange'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
This will apply the orange color when using a default `<UButton />`. You'll need to safelist this color manually in your `nuxt.config.ts` ui options as we won't be able to detect it automatically. You can do so through the `safelistColors` option which defaults to `['primary']`.
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
ui: {
|
||||
safelistColors: ['orange']
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
This can also happen when you bind a dynamic color to a component: `<UBadge :color="color" />`, `<UAvatar :chip-color="statuses[user.status]" />`, etc. In this case, you'll need to safelist the possible color values manually as well.
|
||||
|
||||
## Components
|
||||
|
||||
### `app.config.ts`
|
||||
|
||||
You can find the config of each component in the [`ui.config/`](https://github.com/nuxt/ui/tree/dev/src/runtime/ui.config) directory. You can override those classes in your own `app.config.ts`.
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
container: {
|
||||
constrained: 'max-w-5xl'
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Thanks to [tailwind-merge](https://github.com/dcastil/tailwind-merge), the `app.config.ts` is smartly merged with the default config. This means you don't have to rewrite everything.
|
||||
|
||||
You can change this behavior by setting `strategy` to `override` in your `app.config.ts`:
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
strategy: 'override',
|
||||
button: {
|
||||
color: {
|
||||
white: {
|
||||
solid: 'bg-white dark:bg-gray-900'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### `ui` prop
|
||||
|
||||
Each component has a `ui` prop that allows you to customize everything specifically.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<UContainer :ui="{ constrained: 'max-w-2xl' }">
|
||||
<slot />
|
||||
</UContainer>
|
||||
</template>
|
||||
```
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
You can find the default classes for each component under the `Config` section.
|
||||
::
|
||||
|
||||
Thanks to [tailwind-merge](https://github.com/dcastil/tailwind-merge), the `ui` prop is smartly merged with the config. This means you don't have to rewrite everything.
|
||||
|
||||
For example, the default preset of the `FormGroup` component looks like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"label": {
|
||||
"base": "block font-medium text-gray-700 dark:text-gray-200"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To change the font of the `label`, you only need to write:
|
||||
|
||||
```vue
|
||||
<UFormGroup name="email" label="Email" :ui="{ label: { base: 'font-semibold' } }" />
|
||||
```
|
||||
|
||||
This will smartly replace the `font-medium` by `font-semibold` and prevent any class duplication and any class priority issue.
|
||||
|
||||
You can change this behavior by setting `strategy` to `override` inside the `ui` prop:
|
||||
|
||||
```vue
|
||||
<UButton
|
||||
to="https://github.com/nuxt/ui"
|
||||
:ui="{
|
||||
strategy: 'override',
|
||||
color: {
|
||||
white: {
|
||||
solid: 'bg-white dark:bg-gray-900'
|
||||
}
|
||||
}
|
||||
}"
|
||||
/>
|
||||
```
|
||||
|
||||
### `class` attribute
|
||||
|
||||
You can also use the `class` attribute to add classes to the component.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<UButton label="Button" class="rounded-full" />
|
||||
</template>
|
||||
```
|
||||
|
||||
Again, with [tailwind-merge](https://github.com/dcastil/tailwind-merge), this will smartly merge the classes with the `ui` prop and the config.
|
||||
|
||||
### Default values
|
||||
|
||||
Some component props like `size`, `color`, `variant`, etc. have a default value that you can override in your `app.config.ts`.
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
button: {
|
||||
default: {
|
||||
size: 'md',
|
||||
color: 'gray',
|
||||
variant: 'ghost'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Dark mode
|
||||
|
||||
All the components are styled with dark mode in mind.
|
||||
|
||||
Thanks to [Tailwind CSS dark mode](https://tailwindcss.com/docs/dark-mode#toggling-dark-mode-manually) class strategy and the [@nuxtjs/color-mode](https://github.com/nuxt-modules/color-mode) module, you literally have nothing to do.
|
||||
|
||||
You can disable dark mode by setting the `preference` to `light` instead of `system` in your `nuxt.config.ts`.
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
colorMode: {
|
||||
preference: 'light'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
If you're stuck in dark mode even after changing this setting, you might need to remove the `nuxt-color-mode` entry from your browser's local storage.
|
||||
::
|
||||
|
||||
You can easily build a color mode button by using the `useColorMode` composable from `@nuxtjs/color-mode`.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:color-mode-button
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
const colorMode = useColorMode()
|
||||
const isDark = computed({
|
||||
get () {
|
||||
return colorMode.value === 'dark'
|
||||
},
|
||||
set () {
|
||||
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<UButton
|
||||
:icon="isDark ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
|
||||
color="gray"
|
||||
variant="ghost"
|
||||
aria-label="Theme"
|
||||
@click="isDark = !isDark"
|
||||
/>
|
||||
<template #fallback>
|
||||
<div class="w-8 h-8" />
|
||||
</template>
|
||||
</ClientOnly>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
## Icons
|
||||
|
||||
You can use any icon (100,000+) from [Iconify](https://iconify.design/).
|
||||
|
||||
Some components have an `icon` prop that allows you to add an icon to the component.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<UButton icon="i-heroicons-magnifying-glass" />
|
||||
</template>
|
||||
```
|
||||
|
||||
You can also use the [Icon](/components/icon) component to add an icon anywhere in your app by following this pattern: `i-{collection_name}-{icon_name}`.
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<UIcon name="i-heroicons-moon" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### Collections
|
||||
|
||||
By default, the module uses [Heroicons](https://heroicons.com/) but you can change it from the module options in your `nuxt.config.ts`.
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
ui: {
|
||||
icons: ['mdi', 'simple-icons']
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
Search the icon you want to use on https://icones.js.org built by [@antfu](https://github.com/antfu).
|
||||
::
|
||||
|
||||
Thanks to [@egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons) plugin, only the icons you use in your app will be bundled in your CSS. However, you need to install the icon collections you specified in the `ui.icons` key:
|
||||
|
||||
::code-group
|
||||
|
||||
```bash [pnpm]
|
||||
pnpm i @iconify-json/{collection_name}
|
||||
```
|
||||
|
||||
```bash [yarn]
|
||||
yarn add @iconify-json/{collection_name}
|
||||
```
|
||||
|
||||
```bash [npm]
|
||||
npm install @iconify-json/{collection_name}
|
||||
```
|
||||
|
||||
::
|
||||
|
||||
If you choose to use the full `@iconify/json` icon collection (50MB), you can specifiy `icons: 'all'` or `icons: {}` in your `nuxt.config.ts` to use any icon in your app.
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
export default defineNuxtConfig({
|
||||
ui: {
|
||||
icons: {}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Custom config
|
||||
|
||||
If you have specific needs, like using a custom icon collection, you can use the `icons` option in your `nuxt.config.ts` as an object to override the config of the [@egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons#plugin-options) plugin.
|
||||
|
||||
```ts [nuxt.config.ts]
|
||||
import { getIconCollections } from '@egoist/tailwindcss-icons'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
ui: {
|
||||
icons: {
|
||||
// might solve stretch bug on generate, see https://github.com/egoist/tailwindcss-icons/issues/23
|
||||
extraProperties: {
|
||||
'mask-size': 'contain',
|
||||
'mask-position': 'center'
|
||||
},
|
||||
collections: {
|
||||
foo: {
|
||||
icons: {
|
||||
'arrow-left': {
|
||||
// svg body
|
||||
body: '<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" />',
|
||||
// svg width and height, optional
|
||||
width: 24,
|
||||
height: 24
|
||||
}
|
||||
}
|
||||
},
|
||||
...getIconCollections(['heroicons', 'simple-icons'])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Dynamic icons
|
||||
|
||||
The `Icon` component also has a `dynamic` prop to use the [nuxt-icon](https://github.com/nuxt-modules/icon/) module instead of the [@egoist/tailwindcss-icons](https://github.com/egoist/tailwindcss-icons#plugin-options) plugin.
|
||||
|
||||
Read more about this in the [Icon](/components/icon#dynamic) component page.
|
||||
|
||||
### Defaults
|
||||
|
||||
You can easily replace all the default icons of the components in your `app.config.ts`.
|
||||
|
||||
```ts [app.config.ts]
|
||||
export default defineAppConfig({
|
||||
ui: {
|
||||
button: {
|
||||
default: {
|
||||
loadingIcon: 'i-octicon-sync-24'
|
||||
}
|
||||
},
|
||||
input: {
|
||||
default: {
|
||||
loadingIcon: 'i-octicon-sync-24'
|
||||
}
|
||||
},
|
||||
select: {
|
||||
default: {
|
||||
loadingIcon: 'i-octicon-sync-24',
|
||||
trailingIcon: 'i-octicon-chevron-down-24'
|
||||
}
|
||||
},
|
||||
selectMenu: {
|
||||
default: {
|
||||
selectedIcon: 'i-octicon-check-24'
|
||||
}
|
||||
},
|
||||
notification: {
|
||||
default: {
|
||||
closeButton: {
|
||||
icon: 'i-octicon-x-24'
|
||||
}
|
||||
}
|
||||
},
|
||||
commandPalette: {
|
||||
default: {
|
||||
icon: 'i-octicon-search-24',
|
||||
loadingIcon: 'i-octicon-sync-24',
|
||||
selectedIcon: 'i-octicon-check-24',
|
||||
emptyState: {
|
||||
icon: 'i-octicon-search-24'
|
||||
}
|
||||
}
|
||||
},
|
||||
table: {
|
||||
default: {
|
||||
sortAscIcon: 'i-octicon-sort-asc-24',
|
||||
sortDescIcon: 'i-octicon-sort-desc-24',
|
||||
sortButton: {
|
||||
icon: 'i-octicon-arrow-switch-24'
|
||||
},
|
||||
loadingState: {
|
||||
icon: 'i-octicon-sync-24'
|
||||
},
|
||||
emptyState: {
|
||||
icon: 'i-octicon-database-24'
|
||||
}
|
||||
}
|
||||
},
|
||||
pagination: {
|
||||
default: {
|
||||
firstButton: {
|
||||
icon: 'i-octicon-chevron-left-24'
|
||||
},
|
||||
prevButton: {
|
||||
icon: 'i-octicon-arrow-left-24'
|
||||
},
|
||||
nextButton: {
|
||||
icon: 'i-octicon-arrow-right-24'
|
||||
},
|
||||
lastButton: {
|
||||
icon: 'i-octicon-chevron-right-24'
|
||||
}
|
||||
}
|
||||
},
|
||||
accordion: {
|
||||
default: {
|
||||
openIcon: 'i-octicon-chevron-down-24'
|
||||
}
|
||||
},
|
||||
breadcrumb: {
|
||||
default: {
|
||||
divider: 'i-octicon-chevron-right-24'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user