Theme

GitHub
Eine Headless-Komponente zum Theme-Child-Komponenten.

Bearbeiten

Die Theme-Komponente überschreibt die Standardklassen slot classes und props aller untergeordneten Komponenten, ohne jede einzeln zu modifizieren. Es verwendet den Mechanismus provide/inject von Vue unter der Haube, sodass die Überschreibungen in jeder Tiefe angewendet werden.

Die Theme-Komponente rendert kein HTML-Element, sondern bietet nur Theme-Overrides für ihre Kinder.
Für die Konfiguration des Designs auf App-Ebene empfehlen wir stattdessen die Verwendung der Datei app.config.ts.
Für die Konfiguration des Designs auf App-Ebene empfehlen wir stattdessen die Verwendung der Datei vite.config.ts.

Slot-Klassen

Verwenden Sie die ui-prop, um Slot-Klassen von nachgeordneten Komponenten zu überschreiben. Schlüssel sind Komponentennamen (camelCase) und Werte sind ihre Slot-Klassen-Überschreibungen.

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

Prop Standardeinstellungen: badge{label="4.8+" class="align-text-top"}

Verwenden Sie die props prop, um den Standardwert einer beliebigen prop auf den untergeordneten Komponenten zu überschreiben. Jede Taste wird einem Teil der props dieser Komponente zugeordnet.

<template>
  <UTheme
    :props="{
      button: { color: 'neutral', variant: 'subtle', size: 'lg' },
      tooltip: { delayDuration: 0, arrow: true }
    }"
  >
    <div class="flex items-center gap-2">
      <UTooltip text="Inherits delayDuration from theme">
        <UButton label="Hover me" />
      </UTooltip>
      <UButton label="With icon" icon="i-lucide-rocket" />
      <UButton label="Square" icon="i-lucide-star" square />
    </div>
  </UTheme>
</template>
Explizite Requisiten auf einer Komponente (z.B. <UButton color="primary" />) gewinnen immer über <UTheme :props>. Theme-Standardeinstellungen gelten nur, wenn die Prop nicht explizit übergeben wurde.

Examples (Beispiele)

Multiple Komponenten

Verwenden Sie verschiedene Tasten in ui oder props, um mehrere Komponententypen gleichzeitig zu gestalten.

<template>
  <UTheme
    :props="{
      button: { color: 'neutral', variant: 'outline', size: 'lg' },
      input: { size: 'lg' },
      select: { size: 'lg' }
    }"
    :ui="{
      button: { base: 'rounded-full' },
      input: { base: 'rounded-full' },
      select: { base: 'rounded-full' }
    }"
  >
    <div class="flex items-center gap-2">
      <UButton label="Button" />
      <UInput placeholder="Search..." />
      <USelect placeholder="Select" :items="['Item 1', 'Item 2', 'Item 3']" />
    </div>
  </UTheme>
</template>

Verschachtelte Themen

Verschachteln Sie mehrere Theme-Komponenten, um Overrides zu erstellen. Das innerste Theme hat Vorrang, während nicht überschriebene Schlüssel vom äußeren Theme geerbt werden.

<template>
  <UTheme
    :ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <div class="flex flex-col items-start gap-4 border border-muted p-4 rounded-lg">
      <div class="flex items-center gap-2">
        <UButton label="Outer theme" />
        <UButton label="Outer theme" color="neutral" variant="outline" />
      </div>

      <UTheme
        :ui="{
          button: {
            base: 'font-black uppercase'
          }
        }"
      >
        <div class="border border-muted p-4 rounded-lg">
          <div class="flex items-center gap-2">
            <UButton label="Inner theme" />
            <UButton label="Inner theme" color="neutral" variant="outline" />
          </div>
        </div>
      </UTheme>
    </div>
  </UTheme>
</template>

Explicit priority (Priorität)

Das explizite Setzen einer Prop (einschließlich ui) auf eine einzelne Komponente hat immer Vorrang vor der Theme-Komponente.

<template>
  <UTheme
    :ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <div class="flex items-center gap-2">
      <UButton label="Themed" />
      <UButton label="Overridden" :ui="{ base: 'rounded-none' }" />
    </div>
  </UTheme>
</template>

Deep Propagation (Tiefenausbreitung)

Die Overrides sind für alle abgeleiteten Komponenten verfügbar, unabhängig davon, wie tief sie verschachtelt sind.

<script setup lang="ts">
import MyButton from './MyButton.vue'
</script>

<template>
  <UTheme
    :ui="{
      button: {
        base: 'rounded-full'
      }
    }"
  >
    <UCard :ui="{ body: 'flex items-center gap-2 sm:flex-row flex-col' }">
      <UButton label="Direct child" />
      <MyButton />
    </UCard>
  </UTheme>
</template>
In diesem Beispiel ist MyButton eine benutzerdefinierte Komponente, die eine UButton intern rendert. Die Theme-Overrides gelten weiterhin, da sie sich über den gesamten Komponentenbaum ausbreiten.

Form Komponenten

Verwenden Sie die Designkomponente, um ein konsistentes Styling auf eine Gruppe von Formularkomponenten anzuwenden.

Your public display name.

Used for notifications.

A short description about yourself.

<script setup lang="ts">
import * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'

const schema = z.object({
  name: z.string().min(2, 'Too short'),
  email: z.email('Invalid email'),
  bio: z.string().optional()
})

type Schema = z.output<typeof schema>

const state = reactive<Partial<Schema>>({
  name: 'John Doe',
  email: 'john@example.com',
  bio: undefined
})

const toast = useToast()
async function onSubmit(event: FormSubmitEvent<Schema>) {
  toast.add({ title: 'Saved', description: 'Your profile has been updated.', color: 'success' })
  console.log(event.data)
}
</script>

<template>
  <UTheme
    :props="{
      input: { size: 'lg' },
      textarea: { size: 'lg' }
    }"
    :ui="{
      formField: {
        root: 'flex max-sm:flex-col justify-between gap-4',
        wrapper: 'w-full sm:max-w-xs'
      }
    }"
  >
    <UForm :schema="schema" :state="state" class="space-y-4 w-full" @submit="onSubmit">
      <UFormField label="Name" name="name" description="Your public display name.">
        <UInput v-model="state.name" />
      </UFormField>

      <UFormField label="Email" name="email" description="Used for notifications.">
        <UInput v-model="state.email" type="email" />
      </UFormField>

      <UFormField label="Bio" name="bio" description="A short description about yourself.">
        <UTextarea v-model="state.bio" placeholder="Tell us about yourself" />
      </UFormField>

      <div class="flex justify-end">
        <UButton type="submit">
          Save changes
        </UButton>
      </div>
    </UForm>
  </UTheme>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'

const schema = z.object({
  name: z.string().min(2, 'Too short'),
  email: z.email('Invalid email'),
  bio: z.string().optional()
})

type Schema = z.output<typeof schema>

const state = reactive<Partial<Schema>>({
  name: 'John Doe',
  email: 'john@example.com',
  bio: undefined
})

const toast = useToast()
async function onSubmit(event: FormSubmitEvent<Schema>) {
  toast.add({ title: 'Saved', description: 'Your profile has been updated.', color: 'success' })
  console.log(event.data)
}
</script>

<template>
  <UTheme
    :props="{
      input: { size: 'lg' },
      textarea: { size: 'lg' }
    }"
    :ui="{
      formField: {
        root: 'flex max-sm:flex-col justify-between gap-4',
        wrapper: 'w-full sm:max-w-xs'
      }
    }"
  >
    <UForm :schema="schema" :state="state" class="space-y-4 w-full" @submit="onSubmit">
      <UFormField label="Name" name="name" description="Your public display name.">
        <UInput v-model="state.name" />
      </UFormField>

      <UFormField label="Email" name="email" description="Used for notifications.">
        <UInput v-model="state.email" type="email" />
      </UFormField>

      <UFormField label="Bio" name="bio" description="A short description about yourself.">
        <UTextarea v-model="state.bio" placeholder="Tell us about yourself" />
      </UFormField>

      <div class="flex justify-end">
        <UButton type="submit">
          Save changes
        </UButton>
      </div>
    </UForm>
  </UTheme>
</template>
<UFormField>, <UFieldGroup> und <UAvatarGroup> behalten Vorrang vor <UTheme :props> für size, color und highlight.

Prose-Komponenten

Verwenden Sie den Namensraum prose, um Typografiekomponenten zu gestalten. Schlüssel werden unter prose verschachtelt (z. B. prose.p, prose.code).

Getting started

This is a paragraph with a tighter typographic scale applied through the Theme component.

  • First item
  • Second item
  • Third item
The spacing and font sizes are smaller than the defaults, making it ideal for compact content areas.
<script setup lang="ts">
import { Markdown } from '@comark/vue'

const ui = {
  prose: {
    p: { base: 'my-2.5 text-sm/6' },
    li: { base: 'my-0.5 text-sm/6' },
    ul: { base: 'my-2.5' },
    ol: { base: 'my-2.5' },
    h1: { base: 'text-xl mb-4' },
    h2: { base: 'text-lg mt-6 mb-3' },
    h3: { base: 'text-base mt-4 mb-2' },
    h4: { base: 'text-sm mt-3 mb-1.5' },
    code: { base: 'text-xs' },
    pre: { root: 'my-2.5', base: 'text-xs/5' },
    table: { root: 'my-2.5' },
    hr: { base: 'my-5' }
  }
}

const value = `## Getting started

This is a paragraph with a **tighter typographic scale** applied through the \`Theme\` component.

- First item
- Second item
- Third item

> The spacing and font sizes are smaller than the defaults, making it ideal for compact content areas.`
</script>

<template>
  <UTheme :ui="ui">
    <Markdown :value="value" class="*:first:mt-0 *:last:mb-0" />
  </UTheme>
</template>

API (Englisch)

Props (nicht)

Prop Default Type
props
ThemeDefaults

Per-component prop defaults that flow through useComponentProps to every descendant. Each key maps to a partial of that component's props.

ui
ThemeUI

Per-component slot class overrides (flat shorthand for :props.<name>.ui).

Slots Bearbeiten

Slot Type
default
{}

Changelog (englisch)

No recent changes