UIButton — универсальная кнопка

Компонент UIButton реализует единый стиль кнопок проекта на базе Tailwind CSS и class-variance-authority (CVA). Он поддерживает шесть вариантов оформления, шесть типоразмеров (включая квадратный icon-only), несколько степеней скругления, состояния loading/disabled, а также может рендериться как <button> или как ссылка <a>.

  • Файл: app/components/ui/button/UIButton.vue
  • Варианты/классы: app/components/ui/button/button.ts (buttonVariants)

Быстрый старт

<script setup lang="ts">
  import UIButton from 'components/ui/button/Button.vue'
</script>

<template>
  <UIButton variant="primary" size="md">Отправить</UIButton>
</template>

API

Props

PropTypeПо умолчанию
variant'primary' · 'secondary' · 'neutral' · 'outline' · 'ghost' · 'destructive''primary'
size'xs' · 'sm' · 'md' · 'lg' · 'xl' · 'icon''md'
rounded'md' · 'lg' · 'full''md'
iconPlacement'left' · 'right' · 'only' · undefinedundefined
as'button' · 'a''button'
href?string · undefinedundefined
target?string · undefinedundefined
rel?string · undefinedundefined
ariaLabel?stringundefined
loading?booleanfalse
disabled?booleanfalse
class?stringundefined

Emits

PropTypeПо умолчанию
click(ev: MouseEvent)не срабатывает в состояниях loading/disabled

Slots

PropПо умолчанию
default— текст/контент кнопки
iconслот для иконки; располагать слева/справа/только иконка управляется prop iconPlacement

Поведение и доступность

loading и disabled переводят кнопку в неинтерактивное состояние:

  • Для <button> проставляется атрибут disabled
  • Для <a> добавляется aria-disabled="true" и отключаются pointer-events; обработчик клика предотвращается
  • Режим icon-only (iconPlacement='only') скрывает текст; обязательно задавайте ariaLabel, чтобы описать действие кнопки для скринридеров
  • Кнопка управляет фокус-кольцом через utility-классы focus-visible и проектные токены (см. ниже)

Стили и токены

Основа оформлена через CVA (buttonVariants) и токены, определённые в Tailwind CSS переменных.

  • Базовые классы:
    • inline-flex items-center justify-center gap-2 whitespace-nowrap select-none font-medium transition-colors
    • focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background
  • Варианты (variant):
    • primary
      • bg: var(--btn-default-bg-primary)
      • text: var(--btn-default-text-primary)
      • hover bg: var(--btn-hover-bg-primary)
      • active bg: var(--btn-active-bg-primary)
      • disabled bg: var(--btn-default-bg-disable)
      • disabled text: var(--btn-default-text-disable)
    • secondary
      • bg: var(--btn-default-bg-secondary)
      • text: var(--btn-default-text-secondary)
      • hover bg: var(--btn-hover-bg-secondary)
      • active bg: var(--btn-active-bg-secondary)
      • disabled bg/text: как выше (disable)
    • neutral
      • bg: var(--btn-default-bg-neutral)
      • text: text-foreground
      • hover bg: var(--btn-hover-bg-neutral)
      • active bg: var(--btn-active-bg-neutral)
      • disabled bg/text: disable-токены
    • outline
      • border: var(--input)
      • фон: прозрачный, текст: text-foreground
      • hover/active bg: var(--accent), текст: var(--accent-foreground)
    • ghost
      • фон: прозрачный, текст: text-foreground
      • hover/active bg: var(--accent), текст: var(--accent-foreground)
    • destructive
      • bg-destructive, text-primary-foreground
      • hover:bg-destructive/90, active:bg-destructive/80
      • disabled: disable-токены
  • Размеры (size):
    • xs: h-7 px-2.5 + типографика btn-s
    • sm: h-8 px-3 + btn-s
    • md: h-9 px-4 + btn-m
    • lg: h-10 px-5 + btn-m
    • xl: h-11 px-6 + btn-l
    • icon: h-9 w-9 p-0 (квадратная)
  • Скругление (rounded):
    • md: rounded-var(--elements-radius-m)
    • lg: rounded-var(--elements-radius-l)
    • full: rounded-full
  • Фокус-кольцо:
    • focus-visible:ring-ring
    • focus-visible:ring-offset-2
    • ring-offset-background
  • Прочие состояния:
    • disabled: cursor-not-allowed opacity-50

Примечание: значения var(...) должны быть определены в app/assets/css/tailwind.css (ваши дизайн-токены). Токены вроде bg-destructive, text-foreground, accent/foreground предоставляются слоем Tailwind переменных и shadcn-настройками.

Примеры

Варианты (variant)
Размеры (size)
Скругление (rounded)
Иконка слева/справа/только иконка (iconPlacement)
Состояния loading/disabled
Ссылочный режим (as='a')
Кастомная ширина и utility-классы

Внутренние детали реализации

  • Рендер через динамический тег (<button> или <a>) управляется пропом as
  • При неинтерактивных состояниях клики предотвращаются внутри onClick; для ссылок добавляется pointer-events-none и aria-disabled
  • Спиннер загрузки — <Icon name="lucide:loader-2" class="h-4 w-4 animate-spin" />; он позиционируется поверх контента благодаря relative-позиционированию корневого inline-flex (см. scoped-стили в компоненте)
  • Классы собираются через утилиту cn(...) и CVA-функцию buttonVariants

Советы по настройке темизации

  • Меняйте значения var(--btn-... ) и системных токенов (--accent, --input, --elements-radius-*) в app/assets/css/tailwind.css
  • Для продвинутых кейсов можно расширить button.ts: добавить новые variant/size/rounded в cva и экспортировать типы из ButtonVariantProps
  • Если нужно переопределять спиннер или добавить иконку во время загрузки — можно расширить компонент слотом под loader или условным скрытием внутреннего Icon