# Button Guides

## Patterns

### Primary Form Action

When to use:

- A form needs one clear primary action.

Composition notes:

- Keep the primary action visually stronger than nearby secondary actions.
- Use `type='submit'` deliberately.

Trade-offs:

- Strong action clarity.
- Can become visually noisy if too many buttons compete for emphasis.

```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>
  );
}
```

### Secondary Action Pair

When to use:

- A local flow needs primary and secondary actions side by side.

Composition notes:

- Use a lower-emphasis treatment for cancel or back actions.
- Keep the button texts complementary rather than ambiguous.

Trade-offs:

- Easy to scan.
- Can become confusing if both buttons use the same emphasis.

```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>
  );
}
```

### Navigation With Button Visuals

When to use:

- Navigation needs to look like a button while staying semantically navigational.

Composition notes:

- Use `asChild` with a real anchor.
- Preserve link semantics when the interaction truly navigates.

Trade-offs:

- Strong visual emphasis for navigation.
- Easy to misuse when a plain link would be clearer.

```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>
  );
}
```

## Comparison

### Quick Decision Rule

Use `Button` for explicit actions initiated by the user.

### `Button` vs `Link`

Use `Button` when:

- the action mutates state or submits data

Use `Link` when:

- the interaction primarily navigates

Main trade-off: button is action semantics, while link is navigation semantics.

### `Button` vs `IconButton`

Use `Button` when:

- visible text improves clarity

Use `IconButton` when:

- the action is compact and already recognizable as an icon-only control

Main trade-off: button is clearer, while icon button is denser.

### `Button` vs `ButtonBase`

Use `Button` when:

- product code needs a standard text action surface

Use `ButtonBase` when:

- a lower-level action primitive is needed for custom composition

### Choose This Component When

- The primary job is action, not navigation.
- Visible text helps users understand the action.
- The UI benefits from a standard button surface.
- the component should be the default action choice rather than a low-level primitive

### Do Not Choose This Component When

- The primary job is navigation.
- The action is icon-only and space-constrained.
- The interaction is really a text link in running copy.

## Troubleshooting

### Button Submits The Form Unexpectedly

#### Symptom

The button is inside a form, and clicking it submits the form.

#### Likely Cause

`Button` has no default `type`, so like a native `<button>` it is a submit button inside a form.

#### How To Verify

- Inspect the rendered `type`.
- Check whether the button was meant to submit the form.

#### Fix

- Set `type='button'` when the button should not submit the form.

### Polymorphic Button Behaves Strangely

#### Symptom

The control renders, but the child element does not support the forwarded props as expected.

#### Likely Cause

`asChild` was used with an incompatible child element.

#### How To Verify

- Inspect the rendered child element.
- Check whether it supports the intended props and semantics.

#### Fix

- Use a child that matches the intended semantics, such as an anchor for navigation.
- Keep plain button rendering when polymorphism is unnecessary.

### Button Should Probably Be A Link

#### Symptom

The control works visually, but the interaction is really navigation.

#### Likely Cause

`Button` was chosen for a navigation pattern that should keep link semantics.

#### How To Verify

- Ask whether the primary job is action or navigation.
- Compare the flow with `Link` or `Button asChild`.

#### Fix

- Use `Link` for plain text navigation.
- Use `Button asChild` with a real anchor when button visuals are still needed.
