@codecademy/gamut

68.6.068.6.1-alpha.bc8b32.0
agent-tools/guidelines/components/buttons.md
+agent-tools/guidelines/components/buttons.mdNew file
+91
Index: package/agent-tools/guidelines/components/buttons.md
===================================================================
--- package/agent-tools/guidelines/components/buttons.md
+++ package/agent-tools/guidelines/components/buttons.md
@@ -0,0 +1,91 @@
+# Buttons
+
+Agent reference: which **button component** and which **`variant`** to use. Colors are wired inside each atom — consumers do **not** pass `color`, `bg`, hex, or semantic token names on stock buttons.
+
+**Related docs:** [overview.md](../overview.md) (reading order) · [foundations/color.md](../foundations/color.md) and `gamut-color-mode` skill — semantic tokens for **custom** styled controls only, not stock button atoms · [foundations/modes.md](../foundations/modes.md) — ColorMode / `<Background>` when placing buttons on colored surfaces
+
+**Storybook (UX source of truth):**
+
+- [Atoms / Buttons / Button](https://gamut.codecademy.com/?path=/docs-atoms-buttons-button--docs) — variants, light/dark examples
+- [FillButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-fillbutton--docs) · [StrokeButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-strokebutton--docs) · [TextButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-textbutton--docs) · [IconButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-iconbutton--docs) · [CTAButton](https://gamut.codecademy.com/?path=/docs-atoms-buttons-ctabutton--docs)
+- [Meta / Best practices](https://gamut.codecademy.com/?path=/docs-meta-best-practices--page) — semantic tokens for custom `css` / `variant` / `states`, not prebuilt atoms
+- [UX Writing / Component guidelines / Buttons](https://gamut.codecademy.com/?path=/docs-ux-writing-component-guidelines-buttons--docs) — label copy
+
+## Component selection
+
+| Component      | Use for                                       | Default `variant`                                |
+| -------------- | --------------------------------------------- | ------------------------------------------------ |
+| `FillButton`   | Primary / high-emphasis actions               | `primary`                                        |
+| `StrokeButton` | Secondary / outlined actions                  | `primary` (often pass `secondary` per Storybook) |
+| `TextButton`   | Low-emphasis, inline actions                  | `primary`                                        |
+| `IconButton`   | Icon-only; requires `tip` and accessible name | `secondary`                                      |
+| `CTAButton`    | Marketing / high-visibility CTA only          | `primary` (only option)                          |
+
+## `variant` prop
+
+Shared by `FillButton`, `StrokeButton`, `TextButton`, and `IconButton`. `CTAButton` only supports `primary`.
+
+| `variant`   | Typical use                    |
+| ----------- | ------------------------------ |
+| `primary`   | Submit, main CTA               |
+| `secondary` | Close, cancel, low priority    |
+| `danger`    | Destructive actions            |
+| `interface` | Controls styled like UI chrome |
+
+```tsx
+<FillButton variant="primary">Submit</FillButton>
+<StrokeButton variant="secondary">Cancel</StrokeButton>
+<IconButton icon={SearchIcon} tip="Search" variant="secondary" />
+<CTAButton>Try Pro for free</CTAButton>
+```
+
+## Sizes
+
+`small` | `normal` (default) | `large`
+
+## Key props
+
+| Prop           | Type                                                  | Effect                                           |
+| -------------- | ----------------------------------------------------- | ------------------------------------------------ |
+| `variant`      | `"primary" \| "secondary" \| "danger" \| "interface"` | Color emphasis (see table above)                 |
+| `size`         | `"small" \| "normal" \| "large"`                      | Padding and font size                            |
+| `icon`         | Icon component                                        | Leading or trailing icon (Fill, Stroke, Text)    |
+| `iconPosition` | `"left" \| "right"`                                   | Defaults to left                                 |
+| `disabled`     | boolean                                               | Disabled state styling                           |
+| `href`         | string                                                | Renders as `<a>` tag                             |
+| `tip`          | string                                                | Required on `IconButton` (tooltip + hover label) |
+
+## States
+
+Hover, active, and disabled colors are handled by the component. Do not override state colors with `color` / `bg` props.
+
+## Accessibility — `disabled` vs `aria-disabled`
+
+| Situation                                                           | Use                                                    | Why                                                                                                                                                                                                                                                     |
+| ------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| Button should not be activatable (default)                          | `disabled` prop                                        | Renders native `disabled` on `<button>`; removed from tab order; correct for most forms and actions                                                                                                                                                     |
+| Disabled button **with a tooltip** that must stay readable on focus | `aria-disabled` only — **do not** also pass `disabled` | Native `disabled` blocks keyboard focus, so the tooltip cannot be reached. Gamut disabled **styles** also match `[aria-disabled='true']`. See [ToolTip — With a disabled Button](https://gamut.codecademy.com/?path=/docs-molecules-tips-tooltip--docs) |
+
+```tsx
+// Default — not interactive
+<FillButton disabled>Submit</FillButton>
+
+// Disabled but focusable (e.g. wrapped in ToolTip explaining why)
+<ToolTip id="why-disabled" info="Complete the lesson first">
+  <FillButton aria-describedby="why-disabled" aria-disabled>
+    Submit
+  </FillButton>
+</ToolTip>
+```
+
+- **`href` + `disabled`:** `ButtonBase` (internal) drops `href` and renders a `<button disabled>` — link-style buttons cannot stay anchors while disabled.
+- **`IconButton`:** provide an accessible name via `tip` (used as `aria-label` when `aria-label` is omitted). See ToolTip / IconButton Storybook pages.
+- **`ButtonBase` is not exported** from `@codecademy/gamut` (only the `ButtonBaseElements` type is). Prefer stock atoms; custom button styling belongs in Gamut itself or via `css` / `variant` from `gamut-styles`, not by importing `ButtonBase`.
+
+## Rules
+
+- Use `FillButton` for primary actions and `StrokeButton` for secondary — do not use both at equal weight on the same screen.
+- Reserve `CTAButton` for marketing / high-visibility promotions; do not use it for standard UI actions.
+- Avoid placing buttons in the wrong color-mode context (e.g. light-mode buttons on a navy band without `<Background>`). See [modes.md](../foundations/modes.md).
+- Every interactive `Card` wrapped in `<Anchor>` should have `isInteractive` — not a button inside.
+- Do not set `color`, `bg`, or hex on stock button components. For custom styled controls, follow [color.md](../foundations/color.md) and `gamut-styles` utilities — do not import internal `ButtonBase`.