# Button: Руководства

## Паттерны

### Основное действие формы

Когда использовать:

- Форме нужно одно ясное основное действие.

Заметки по композиции:

- Делайте основное действие визуально сильнее соседних второстепенных.
- Используйте `type='submit'` осознанно.

Компромиссы:

- Действие выглядит однозначно.
- Интерфейс становится визуально шумным, если слишком много кнопок соревнуются за внимание.

```tsx
import { Button, Label, TextField, TextFieldInput } from '@vega-ui/react';
import { FormEvent, useState } from 'react';

export default function FormFooterActions() {
  const [submitted, setSubmitted] = useState('');

  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const data = new FormData(event.currentTarget);
    setSubmitted(`${data.get('workspace')} (${data.get('slug')})`);
  };

  return (
    <form
      onSubmit={handleSubmit}
      onReset={() => setSubmitted('')}
      style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-12)', width: '100%' }}
    >
      <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-8)' }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-3)' }}>
          <Label htmlFor='workspace-name'>Workspace name</Label>
          <TextField>
            <TextFieldInput id='workspace-name' name='workspace' defaultValue='Acme Design' required />
          </TextField>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-3)' }}>
          <Label htmlFor='workspace-slug'>URL slug</Label>
          <TextField>
            <TextFieldInput id='workspace-slug' name='slug' defaultValue='acme-design' pattern='[a-z0-9-]+' required />
          </TextField>
        </div>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-4)' }}>
        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 'var(--spacing-4)' }}>
          <Button type='reset' variant='secondary' appearance='ghost'>Reset</Button>
          <Button type='submit'>Save workspace</Button>
        </div>
        <output style={{ color: 'var(--label-secondary)', textAlign: 'end', overflowWrap: 'anywhere' }}>
          {submitted === '' ? 'Not saved yet' : `Saved: ${submitted}`}
        </output>
      </div>
    </form>
  );
}
```

### Пара с второстепенным действием

Когда использовать:

- Локальному сценарию нужны основное и второстепенное действия рядом.

Заметки по композиции:

- Для отмены или возврата используйте менее акцентное оформление.
- Тексты кнопок должны дополнять друг друга, а не путать.

Компромиссы:

- Легко считывается.
- Сбивает с толку, если обе кнопки одинаково акцентны.

```tsx
import { Button } from '@vega-ui/react';

export default function ActionHierarchy() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-4)', width: '100%' }}>
      <Button type='button' fullWidth>Publish article</Button>
      <Button type='button' fullWidth variant='secondary' appearance='ghost'>Save draft</Button>
      <Button type='button' fullWidth variant='secondary' appearance='ghost'>Preview</Button>
      <Button type='button' fullWidth variant='secondary' appearance='transparent'>Discard</Button>
    </div>
  );
}
```

### Навигация с видом кнопки

Когда использовать:

- Навигация должна выглядеть как кнопка, но семантически оставаться навигацией.

Заметки по композиции:

- Используйте `asChild` с настоящей ссылкой.
- Сохраняйте семантику ссылки, если взаимодействие действительно ведёт на другую страницу.

Компромиссы:

- Сильный визуальный акцент для навигации.
- Легко злоупотребить там, где обычная ссылка была бы понятнее.

```tsx
import { Button, Icon } from '@vega-ui/react';
import { ArrowRightIcon, ExternalLinkIcon } from '@vega-ui/icons';
import './examples.css';

export default function NavigationWithButtonVisuals() {
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--spacing-4)' }}>
      <Button asChild>
        <a href='/onboarding/import'>
          Import contacts
          <Icon size='sm' className='directionalIcon'><ArrowRightIcon /></Icon>
        </a>
      </Button>
      <Button asChild variant='secondary' appearance='ghost'>
        <a href='https://status.example.com' target='_blank' rel='noreferrer'>
          Status page
          <Icon size='sm'><ExternalLinkIcon /></Icon>
        </a>
      </Button>
    </div>
  );
}
```

## Сравнение

### Быстрое правило выбора

Используйте `Button` для явных действий, которые инициирует пользователь.

### `Button` или `Link`

Используйте `Button`, когда:

- действие меняет состояние или отправляет данные

Используйте `Link`, когда:

- взаимодействие в первую очередь ведёт на другую страницу

Главный компромисс: у кнопки семантика действия, у ссылки — семантика навигации.

### `Button` или `IconButton`

Используйте `Button`, когда:

- видимый текст делает действие понятнее

Используйте `IconButton`, когда:

- действие компактное и уже узнаваемо как контрол из одной иконки

Главный компромисс: кнопка понятнее, кнопка-иконка компактнее.

### `Button` или `ButtonBase`

Используйте `Button`, когда:

- продуктовому коду нужна стандартная текстовая поверхность действия

Используйте `ButtonBase`, когда:

- для кастомной композиции нужен низкоуровневый примитив действия

### Выбирайте этот компонент, когда

- Основная задача — действие, а не навигация.
- Видимый текст помогает понять действие.
- Интерфейсу подходит стандартная поверхность кнопки.
- компонент должен быть выбором по умолчанию для действия, а не низкоуровневым примитивом

### Не выбирайте этот компонент, когда

- Основная задача — навигация.
- Действие обозначено только иконкой и места мало.
- На самом деле это текстовая ссылка в основном тексте.

## Решение проблем

### Кнопка неожиданно отправляет форму

#### Симптом

Кнопка находится внутри формы, и клик по ней отправляет форму.

#### Вероятная причина

У `Button` нет `type` по умолчанию, поэтому, как и нативный `<button>`, внутри формы она работает как кнопка отправки.

#### Как проверить

- Посмотрите отрендеренный `type`.
- Проверьте, должна ли кнопка отправлять форму.

#### Решение

- Задайте `type='button'`, если кнопка не должна отправлять форму.

### Полиморфная кнопка ведёт себя странно

#### Симптом

Контрол рендерится, но дочерний элемент не поддерживает передаваемые пропсы так, как ожидалось.

#### Вероятная причина

`asChild` использован с несовместимым дочерним элементом.

#### Как проверить

- Изучите отрендеренный дочерний элемент.
- Проверьте, поддерживает ли он нужные пропсы и семантику.

#### Решение

- Используйте дочерний элемент с подходящей семантикой, например ссылку для навигации.
- Оставьте обычный рендер кнопки, если полиморфизм не нужен.

### Кнопка, вероятно, должна быть ссылкой

#### Симптом

Визуально контрол работает, но на самом деле это навигация.

#### Вероятная причина

`Button` выбран для навигационного паттерна, которому нужна семантика ссылки.

#### Как проверить

- Определите, что главное: действие или навигация.
- Сравните сценарий с `Link` или `Button asChild`.

#### Решение

- Используйте `Link` для обычной текстовой навигации.
- Используйте `Button asChild` с настоящей ссылкой, если вид кнопки всё же нужен.
