Componentes customizados

Aprenda a personalizar los componentes de la interfaz de usuario de Nuxt con la API de Tailwind Variants para un estilo avanzado, flexible y fácil de mantener.

Variantes de ## Tailwind

Los componentes de la interfaz de usuario de Nuxt se diseñan utilizando la API Tailwind Variants, que proporciona una forma poderosa de crear variantes y administrar estilos de componentes.

Slots

Los componentes pueden tener múltiples slots, cada uno representando un elemento HTML distinto o sección dentro del componente.

Tomemos como ejemplo el componente Card que tiene múltiples ranuras:

export default {
  slots: {
    root: 'rounded-lg overflow-hidden',
    header: 'p-4 sm:px-6',
    title: 'text-highlighted font-semibold',
    description: 'mt-1 text-muted text-sm',
    body: 'p-4 sm:p-6',
    footer: 'p-4 sm:px-6'
  }
}
Los componentes reales también llevan protectores v-if en cada ranura y el tema define los estilos variant en la parte superior de las ranuras.

En este caso, el tema solo define la ranura base como el componente Container por ejemplo:

export default {
  base: 'w-full max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8'
}
Expone una sola clave base en lugar de una clave por ranura. Link y [Iconxph072/docs/components/icon) son las excepciones: no tienen prop ui, así que use el [class propxph076) para anular sus estilos.

Variaciones

Los componentes soportan variants, que ajusta dinámicamente los estilos de diferentes slots basados en los accesorios de los componentes.

Por ejemplo, el componente Avatar utiliza una variante size para controlar su apariencia:

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

De esta manera, el accesorio size aplicará los estilos correspondientes a la ranura root:

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

Variantes por defecto

La propiedad defaultVariants establece el valor por defecto para cada variante cuando no se pasa ningún prop.

Por ejemplo, el componente Avatar tiene su tamaño predeterminado establecido en 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'
  }
}
Puede utilizar la opción theme.defaultVariants en su nuxt.config.ts para anular los valores size y color predeterminados de cada componente que utilice md y primary.
Puede utilizar la opción theme.defaultVariants en su vite.config.ts para anular los valores size y color predeterminados de cada componente que utilice md y primary.

Variantes de compuesto

Algunos componentes usan la propiedad compoundVariants para aplicar clases cuando se cumplen varias condiciones de variante al mismo tiempo.

Por ejemplo, el componente Button utiliza la propiedad compoundVariants para aplicar clases para una combinación específica de color y 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 outline-${color}/25 focus-visible:outline-3 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 outline-inverted/25 focus-visible:outline-3 focus-visible:ring-inverted'
    }
  ],
  defaultVariants: {
    color: 'primary',
    variant: 'solid'
  }
})

Personalizar el tema

Hay varias formas de personalizar la apariencia de los componentes de la interfaz de usuario de Nuxt, puede hacerlo para todos los componentes a la vez o por componente.

Tailwind Variants usa tailwind-merge bajo el capó para combinar clases para que no tenga que preocuparse por clases en conflicto.
Puede explorar el tema para cada componente de dos maneras:
  • Compruebe la sección Theme en la documentación de cada componente. Examine el código fuente directamente en el repositorio de GitHub en src/theme.

Configuración global

Puede anular el tema de los componentes de forma global dentro de su app.config.ts utilizando la misma estructura que el objeto de tema.

Puede anular el tema de los componentes de forma global dentro de su vite.config.ts utilizando la misma estructura que el objeto de tema.

Puede personalizar el xslots, variants, compoundVariants y xph2444xdefaultVariants](#default-variants) de un componente para cambiar el tema predeterminado de un componente:

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 '@nuxt/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'
          }
        }
      }
    })
  ]
})
En este ejemplo, font-bold reemplaza a font-medium en todos los botones, size-4 reemplaza a la clase size-5 en el icono principal cuando size="md" y ring-default hover:bg-accented reemplaza a ring-accented hover:bg-elevated cuando color="neutral" y variant="outline".

De forma predeterminada, estas clases se combinan con los valores predeterminados del componente.También puede establecer una ranura para una función para reemplazarlos en su lugar.Recibe las clases predeterminadas de la ranura como argumento, por lo que puede reutilizar parte de ellas.Las clases de variants y compoundVariants aún se aplican en la parte superior, exactamente como cuando pasa una cadena.

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 '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        button: {
          slots: {
            label: () => 'text-base font-bold'
          }
        }
      }
    })
  ]
})
Establece una ranura para una función en un solo lugar. Nuxt combina el app.config.ts de cada layer con defuFn, que llama a tu función con cualquier valor que la clave ya tenga más abajo y mantiene solo el resultado.
Para eliminar las clases predeterminadas de todos los componentes a la vez, utilice la opción theme.unstyled en su nuxt.config.ts.
Para eliminar las clases predeterminadas de todos los componentes a la vez, utilice la opción theme.unstyled en su vite.config.ts.

Componente ### Theme

El componente Theme anula los slots y los valores predeterminados de prop para todos sus descendientes, sin afectar al resto de la aplicación. pero los accesorios ui y class aún lo ganan. Las tragamonedas aceptan la misma forma de función para reemplazar sus clases en lugar de fusionarse. Se resuelve en el mismo punto que el ui prop, por lo que se comporta de la misma manera.

<template>
  <UTheme
    :ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <div class="flex items-center gap-2">
      <UButton label="Button" color="neutral" />
      <UButton label="Button" color="neutral" variant="outline" />
      <UButton label="Button" color="neutral" variant="subtle" />
    </div>
  </UTheme>
</template>

xui Prop.

También puede anular el slots de un componente usando el prop. ui Esto tiene prioridad sobre la configuración global y el variants resuelto.

<template>
  <UButton
    trailing-icon="i-lucide-chevron-right"
    size="md"
    color="neutral"
    variant="outline"
    :ui="{
      trailingIcon: 'rotate-90 size-3'
    }"
  >
    Button
  </UButton>
</template>
En este ejemplo, la ranura trailingIcon se sobrescribe con size-3 a pesar de que la variante de tamaño md le aplicaría una clase size-5.

Un valor slot también puede ser una función para reemplazar sus clases en lugar de fusionarlas:

<template>
  <UButton :ui="{ label: () => 'text-base font-bold' }" label="Button" />
</template>
El prop ui se resuelve después del variants, por lo que a diferencia de la configuración global, una función aquí reemplaza las clases resolved de la ranura. Su argumento contiene lo que coinciden los variants y compoundVariants. Un prop class en la misma ranura todavía se combina en la parte superior de las clases devueltas.

xclass Prop.

Utilice el prop class para anular las clases de la ranura root o base. Esto tiene prioridad sobre la configuración global y la resolución de variants.

<template>
  <UButton class="font-bold rounded-full">Button</UButton>
</template>
En este ejemplo, la clase font-bold anulará la clase font-medium predeterminada en este botón.