Personalizar componentes

Aprenda a personalizar os componentes do Nitro UI com a API do Tailwind Variants para uma estilização avançada, flexível e de fácil manutenção.

Tailwind Variants

Os componentes do Nitro UI são estilizados usando a API do Tailwind Variants, que oferece uma maneira poderosa de criar variantes e gerenciar os estilos dos componentes.

Slots

Os componentes podem ter vários slots, cada um representando um elemento HTML ou seção distinta dentro do componente. Esses slots permitem inserção de conteúdo e estilização flexíveis.

Vamos usar como exemplo o componente Card, que tem vários slots:

export default {
  slots: {
    root: 'bg-default ring ring-default divide-y divide-default rounded-lg',
    header: 'p-4 sm:px-6',
    body: 'p-4 sm:p-6',
    footer: 'p-4 sm:px-6'
  }
}

Alguns componentes não têm slots; eles são compostos apenas por um único elemento raiz. Nesse caso, o tema define apenas o slot base, como o componente Container, por exemplo:

export default {
  base: 'max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8'
}
Componentes sem slots não têm a prop ui; apenas a prop class está disponível para sobrescrever os estilos.

Variantes

Os componentes suportam variants, que permitem ajustar dinamicamente os estilos dos diferentes slots com base nas props do componente.

Por exemplo, o componente Avatar usa uma variante size para controlar sua aparência:

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-elevated',
    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'
  }
}

Dessa forma, a prop size aplicará os estilos correspondentes ao slot root:

<template>
  <NAvatar src="https://github.com/nuxt.png" size="lg" />
</template>

Variantes padrão

A propriedade defaultVariants define o valor padrão de cada variante quando nenhuma prop é passada.

Por exemplo, o componente Avatar tem seu tamanho padrão definido como md:

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-elevated',
    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'
  }
}
Você pode usar a opção theme.defaultVariants no seu nuxt.config.ts para sobrescrever os valores padrão de size e color de todos os componentes de uma vez.
Você pode usar a opção theme.defaultVariants no seu vite.config.ts para sobrescrever os valores padrão de size e color de todos os componentes de uma vez.

Variantes compostas

Alguns componentes usam a propriedade compoundVariants para aplicar classes quando várias condições de variante são atendidas ao mesmo tempo.

Por exemplo, o componente Button usa a propriedade compoundVariants para aplicar classes a uma combinação específica de color e variant:

src/theme/button.ts
import type { ModuleOptions } from '../module'

export default (options: Required<ModuleOptions>) => ({
  slots: {
    base: ['rounded-md font-medium inline-flex items-center disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75', options.theme.transitions && 'transition-colors']
  },
  variants: {
    color: {
      ...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, ''])),
      neutral: ''
    },
    variant: {
      solid: '',
      outline: '',
      soft: '',
      subtle: '',
      ghost: '',
      link: ''
    }
  },
  compoundVariants: [
    ...(options.theme.colors || []).map((color: string) => ({
      color,
      variant: 'outline',
      class: `ring ring-inset ring-${color}/50 text-${color} hover:bg-${color}/10 active:bg-${color}/10 disabled:bg-transparent aria-disabled:bg-transparent dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus:outline-none focus-visible:ring-2 focus-visible:ring-${color}`
    })),
    {
      color: 'neutral',
      variant: 'outline',
      class: 'ring ring-inset ring-accented text-default bg-default hover:bg-elevated active:bg-elevated disabled:bg-default aria-disabled:bg-default focus:outline-none focus-visible:ring-2 focus-visible:ring-inverted'
    }
  ],
  defaultVariants: {
    color: 'primary',
    variant: 'solid'
  }
})

Personalizar o tema

Você tem várias maneiras de personalizar a aparência dos componentes do Nitro UI: pode fazer isso para todos os componentes de uma vez ou individualmente por componente.

O Tailwind Variants usa o tailwind-merge internamente para mesclar classes, então você não precisa se preocupar com classes conflitantes.
Você pode explorar o tema de cada componente de duas maneiras:
  • Check the Theme section in the documentation of each individual component.
  • Browse the source code directly in the GitHub repository at src/theme.

Configuração global

Você pode sobrescrever o tema dos componentes globalmente dentro do seu app.config.ts usando exatamente a mesma estrutura do objeto de tema.

Você pode sobrescrever o tema dos componentes globalmente dentro do seu vite.config.ts usando exatamente a mesma estrutura do objeto de tema.

Você pode personalizar os slots, variants, compoundVariants e defaultVariants de um componente para alterar o tema padrão dele:

app/app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      slots: {
        base: 'font-bold'
      },
      variants: {
        size: {
          md: {
            leadingIcon: 'size-4'
          }
        }
      },
      compoundVariants: [{
        color: 'neutral',
        variant: 'outline',
        class: 'ring-default hover:bg-accented'
      }],
      defaultVariants: {
        color: 'neutral',
        variant: 'outline'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nitro/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        button: {
          slots: {
            base: 'font-bold'
          },
          variants: {
            size: {
              md: {
                leadingIcon: 'size-4'
              }
            }
          },
          compoundVariants: [{
            color: 'neutral',
            variant: 'outline',
            class: 'ring-default hover:bg-accented'
          }],
          defaultVariants: {
            color: 'neutral',
            variant: 'outline'
          }
        }
      }
    })
  ]
})
Neste exemplo, font-bold sobrescreve font-medium em todos os botões, size-4 sobrescreve a classe size-5 no ícone à esquerda quando size="md", e ring-default hover:bg-accented sobrescreve ring-accented hover:bg-elevated quando color="neutral" e variant="outline". Os botões agora usam por padrão color="neutral" e variant="outline".

Por padrão, essas classes são mescladas com os padrões do componente. Você também pode definir um slot como uma função para substituir suas classes por completo. Ela recebe as classes padrão resolvidas como argumento, então você pode reutilizar parte delas se necessário.

app/app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      slots: {
        label: () => 'text-base font-bold'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nitro/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        button: {
          slots: {
            label: () => 'text-base font-bold'
          }
        }
      }
    })
  ]
})
Para remover as classes padrão de todos os componentes de uma vez, use a opção theme.unstyled.

Componente de tema

O componente Theme sobrescreve os slots e os valores padrão de props de todos os seus descendentes, sem afetar o resto do app. Isso tem prioridade sobre a configuração global, mas as props ui e class ainda prevalecem sobre ele. Os slots aceitam a mesma forma de função para substituir suas classes em vez de mesclá-las.

ui prop

Você também pode sobrescrever os slots de um componente usando a prop ui. Isso tem prioridade tanto sobre a configuração global quanto sobre as variants resolvidas.

<template>
  <NButton
    trailing-icon="i-lucide-chevron-right"
    size="md"
    color="neutral"
    variant="outline"
    :ui="{
      trailingIcon: 'rotate-90 size-3'
    }"
  >
    Button
  </NButton>
</template>
Neste exemplo, o slot trailingIcon é sobrescrito com size-3, mesmo que a variante de tamanho md fosse aplicar a ele uma classe size-5.

O valor de um slot também pode ser uma função para substituir suas classes em vez de mesclá-las, da mesma forma que na configuração global:

<template>
  <NButton :ui="{ label: () => 'text-base font-bold' }" label="Button" />
</template>

class prop

A prop class permite sobrescrever as classes do slot root ou base. Isso tem prioridade tanto sobre a configuração global quanto sobre as variants resolvidas.

<template>
  <NButton class="font-bold rounded-full">Button</NButton>
</template>
Neste exemplo, a classe font-bold sobrescreverá a classe padrão font-medium neste botão.