구성 요소 사용자화

Tailwind Variants API를 사용하여 고급, 유연성 및 유지 관리 가능한 스타일 지정을 위해 Nuxt UI 구성 요소를 사용자 정의하는 방법을 알아봅니다.

TAILWIND 변형

Nuxt UI 구성요소는 변형을 작성하고 구성요소 스타일을 관리할 수 있는 강력한 방법을 제공하는 [Tailwind Variants](https://www.tailwind-variants.org/xph04x API를 사용하여 스타일을 지정합니다.

슬롯

구성 요소에는 여러 slots가 있을 수 있으며 각 구성 요소는 구성 요소 내의 고유한 HTML 요소 또는 섹션을 나타냅니다. 이러한 슬롯을 사용하면 내용을 유연하게 삽입하고 스타일 지정할 수 있습니다.

Card 구성 요소를 여러 슬롯이 있는 예로 들어 보겠습니다.

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'
  }
}
실제 구성 요소는 각 슬롯에 v-if 가드를 가지고 있으며 테마는 슬롯 상단에 variant 스타일을 정의합니다.

일부 구성 요소는 슬롯이 없으며 단일 루트 요소로 구성됩니다. 이 경우 테마는 Container 구성 요소와 같이 base 슬롯을 정의합니다.

export default {
  base: 'w-full max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8'
}
슬롯이 없는 구성요소는 여전히 ui prop를 가지고 있습니다. 슬롯당 하나의 키가 아닌 단일 base 키를 노출합니다. Link 및 Icon는 prop0760x는 prop 스타일을 무시하므로 prop 스타일을 사용하지 않습니다.

변형 변수

구성 요소는 구성 요소 소품에 따라 다양한 slots의 스타일을 동적으로 조정하는 variants를 지원합니다.

예를 들어, Avatar 구성 요소는 size 변형을 사용하여 모양을 제어합니다.

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

이렇게 하면 size prop은 root 슬롯에 해당 스타일을 적용합니다.

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

기본 변수

defaultVariants 속성은 prop이 전달되지 않을 때 각 변형에 대한 기본값을 설정합니다.

예를 들어, Avatar 구성 요소의 기본 크기는 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'
  }
}
nuxt.config.ts에서 theme.defaultVariants 옵션을 사용하여 md 및 primary를 사용하는 모든 구성 요소의 기본 size 및 color를 재정의할 수 있습니다.
vite.config.ts에서 theme.defaultVariants 옵션을 사용하여 md 및 primary를 사용하는 모든 구성 요소의 기본 size 및 color를 재정의할 수 있습니다.

복합 변형

일부 구성 요소에서는 compoundVariants 속성을 사용하여 여러 변형 조건이 동시에 충족될 때 클래스를 적용합니다.

예를 들어, Button 구성 요소는 compoundVariants 속성을 사용하여 특정 color 및 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'
  }
})

사용자 지정 테마

Nuxt UI 구성 요소의 모양을 사용자 정의하는 여러 가지 방법이 있으며 모든 구성 요소에 대해 한 번에 또는 구성 요소별로 작업할 수 있습니다.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.

Tailwind Variants는 후드 아래에 tailwind-merge를 사용하여 클래스를 병합하므로 충돌하는 클래스에 대해 걱정할 필요가 없습니다.
다음 두 가지 방법으로 각 구성 요소의 주제를 탐색할 수 있습니다.
  • 각 개별 구성 요소에 대한 설명서에서 Theme 섹션을 확인합니다.
  • xGitHub 리포지토리에서 직접 소스 코드를 찾습니다.[src/themexph22xhttps://github.com/nuxt/ui/tree/v4/src/themexph24x.

Global 구성

테마 객체와 정확히 동일한 구조를 사용하여 app.config.ts 내부의 구성 요소 주제를 전역적으로 재정의할 수 있습니다.

테마 객체와 정확히 동일한 구조를 사용하여 vite.config.ts 내부의 구성 요소 주제를 전역적으로 재정의할 수 있습니다.

slots, variants, 및 [defaultVariants](를 사용자 정의 할 수 있습니다.

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'
          }
        }
      }
    })
  ]
})
이 예에서 font-bold는 모든 단추에서 font-medium를 재정의하고, size="md" 및 ring-default hover:bg-accented가 ring-accented hover:bg-elevated를 재정의하면 size-5는 선행 아이콘의 size-5 클래스를 재정의합니다. 이제 기본적으로 color="neutral" 및 variant="outline"로 설정됩니다.

기본적으로 이러한 클래스는 구성 요소의 기본값에 병합됩니다. 슬롯을 함수로 설정하여 대신 대체할 수도 있습니다. 슬롯의 기본 클래스를 인수로 받으므로 일부를 재사용할 수 있습니다. variants 및 compoundVariants의 클래스는 문자열을 전달할 때와 마찬가지로 맨위에 적용됩니다.

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'
          }
        }
      }
    })
  ]
})
슬롯을 한 위치에서만 함수로 설정합니다. Nuxt는 모든 layer의 app.config.ts를 defuFn와 병합합니다. 이 값은 키가 이미 낮은 값으로 함수를 호출하고 결과만 유지합니다. 그런 다음 Nuxt UI는 일반 문자열을 읽으므로 클래스를 대체하지 않고 기본값으로 병합합니다.
모든 구성 요소에서 기본 클래스를 한 번에 제거하려면 nuxt.config.ts에서 theme.unstyled 옵션을 사용하십시오.
모든 구성 요소에서 기본 클래스를 한 번에 제거하려면 vite.config.ts에서 theme.unstyled 옵션을 사용하십시오.

Theme 구성요소

Theme 구성 요소는 응용 프로그램의 나머지 부분에 영향을 주지 않고 모든 하위 항목에 대한 슬롯과 prop 기본값을 재정의합니다. 이것은 전역 구성보다 우선합니다. 그러나 ui와 class props는 여전히 승리합니다. 슬롯은 병합 대신 클래스를 대체하기 위해 동일한 함수 형태를 사용합니다. ui와 동일한 시점에서 해결됩니다. prop 같은 동작을 합니다.

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

ui prop

또한 ui prop를 사용하여 구성 요소의 slots를 재정의할 수 있습니다. 이는 전역 구성 및 해결된 variants 모두에 우선합니다.

<template>
  <UButton
    trailing-icon="i-lucide-chevron-right"
    size="md"
    color="neutral"
    variant="outline"
    :ui="{
      trailingIcon: 'rotate-90 size-3'
    }"
  >
    Button
  </UButton>
</template>
이 예제에서 trailingIcon 슬롯은 md 크기 변형이 size-5 클래스를 적용하더라도 size-3로 덮어씁니다.

슬롯 값은 클래스를 병합하는 대신 클래스를 대체하는 함수일 수도 있습니다.

<template>
  <UButton :ui="{ label: () => 'text-base font-bold' }" label="Button" />
</template>
ui prop은 variants 이후에 해결되므로 전역 설정과는 달리 여기서 함수는 슬롯의 resolved 클래스를 대체합니다. 이 인수에는 variants와 compoundVariants가 일치하는 것이 포함됩니다. 동일한 슬롯에 있는 class prop은 반환된 클래스 위에 병합됩니다.

class prop

class prop을 사용하여 root 또는 base 슬롯의 클래스를 덮어씁니다. 이것은 전역 구성과 해결된 variants 모두에 우선합니다.

<template>
  <UButton class="font-bold rounded-full">Button</UButton>
</template>
이 예제에서는 font-bold 클래스가 이 버튼의 기본 font-medium 클래스를 재정의합니다.