# Button Component

A polymorphic button component that can render as either a native `<button>` element for interactive actions or an `<a>` element for navigation, with full TypeScript type safety through discriminated unions.

## Import path
```tsx
import Button from '@hubspot/cms-component-library/Button';
```

## Purpose

The Button component provides a unified interface for creating interactive buttons and styled links in HubSpot CMS projects. It solves the common challenge of maintaining visual consistency between clickable elements that perform different functions (navigation vs. actions). `buttonType="link"` should be used most of the time and is default. `buttonType="button"` should only be used when an onClick handler is needed.

## Component Structure

```
Button/
├── index.tsx                     # Main component with render logic
├── types.ts                      # TypeScript type definitions (discriminated unions)
├── ContentFields.tsx             # HubSpot field definitions for content
├── StyleFields.tsx               # HubSpot field definitions for styling
├── index.module.scss             # CSS module with design tokens
└── stories/
    ├── Button.AsButton.stories.tsx  # Interactive button examples
    ├── Button.AsLink.stories.tsx    # Link navigation examples
    ├── ButtonArgs.ts                 # Storybook argument types
    ├── ButtonDecorator.tsx           # Storybook decorator
    └── ButtonDecorator.module.css    # Decorator styles
```

## Components

### Button (Main Component)

**Purpose:** Polymorphic component that renders either a `<button>` or `<a>` element based on the `buttonType` prop.

**Base Props (shared by both types):**
```tsx
{
  variant?: 'primary' | 'secondary' | 'tertiary';  // Visual style variant
  className?: string;                               // Additional CSS classes
  style?: React.CSSProperties;                      // Inline styles
  children?: React.ReactNode;                       // Button text/content
  iconFieldPath?: string;                           // Path to icon in HubSpot fields
  iconPosition?: 'left' | 'right';                  // Icon placement
  iconSize?: number;                                // Icon size in pixels
  showIcon?: boolean;                               // Toggle icon visibility
  iconPurpose?: 'SEMANTIC' | 'DECORATIVE';         // Icon accessibility role
  iconTitle?: string;                               // Icon title for screen readers
}
```

**Button Type (`buttonType="button"`) - Additional Props:**
```tsx
{
  buttonType: 'button';           // Renders as <button> element
  onClick?: () => void;           // Click handler (requires JS islands)
  disabled?: boolean;             // Disables button interaction
}
```

**Link Type (`buttonType="link"`) - Additional Props:**
```tsx
{
  buttonType: 'link';                              // Renders as <a> element
  href?: string;                                   // Link destination URL
  target?: '_self' | '_blank' | '_parent' | '_top'; // Link target behavior
  rel?: string;                                    // Link relationship (e.g., 'noopener noreferrer')
}
```

## Usage Examples

### Basic Interactive Button

Custom Component wrapper
```tsx
import Button from '@hubspot/cms-component-library/Button';

export default function CustomButtonIsland({buttonType, ...rest}){

  // AI / User can now define interactive state or click handlers
  const onClickHandler = () => {
    alert('Button Clicked');
  }

  return <Button buttonType="button" {...rest} onClick={onClickHandler} />
}
```

Module file
```tsx
import CustomButtonIsland from './path/to/created/CustomButtonIsland?island';
import { Island } from '@hubspot/cms-components'

...

<Island module={CustomButtonIsland} {...props}>

...

```



### Basic Link Button

```tsx
<Button
  buttonType="link"
  variant="primary"
  href="https://www.hubspot.com"
  target="_self"
>
  Visit HubSpot
</Button>
```

### External Link (New Tab)

```tsx
<Button
  buttonType="link"
  variant="primary"
  href="https://www.hubspot.com"
  target="_blank"
  rel="noopener noreferrer"
>
  Open in New Tab
</Button>
```

### Button with Icon (Right Position)

```tsx
<Button
  buttonType="button"
  variant="primary"
  onClick={handleClick}
  showIcon={true}
  iconFieldPath="icon"
  iconPosition="right"
  iconSize={18}
  iconPurpose="DECORATIVE"
>
  Next Step
</Button>
```

### Button with Icon (Left Position)

```tsx
<Button
  buttonType="link"
  variant="secondary"
  href="/back"
  showIcon={true}
  iconFieldPath="icon"
  iconPosition="left"
  iconSize={18}
  iconPurpose="SEMANTIC"
  iconTitle="Go back"
>
  Back
</Button>
```

### Disabled Button

```tsx
<Button
  buttonType="button"
  variant="primary"
  disabled={true}
  onClick={handleClick}
>
  Submit (disabled)
</Button>
```

### With Custom Styling

```tsx
<Button
  buttonType="link"
  variant="primary"
  href="/custom"
  className="custom-button-class"
  style={{ maxWidth: '300px' }}
>
  Custom Styled Button
</Button>
```

## HubSpot CMS Integration

### Field Definitions

The Button component provides field definitions for easy integration with HubSpot CMS modules.

#### ContentFields.tsx

Configurable props for customizing field labels, names, and defaults:

```tsx
<Button.ContentFields
  buttonTextLabel="Button text"
  buttonTextName="buttonText"
  buttonTextDefault="Click me"
  buttonLinkLabel="Button link"
  buttonLinkName="buttonLink"
  buttonLinkDefault={{
    url: {
      type: 'EXTERNAL',
      content_id: null,
      href: 'https://www.hubspot.com',
    },
  }}
  showButtonLink={true}
  iconLabel="Button icon"
  iconName="icon"
  iconDefault={/* icon default */}
  showIconLabel="Show button icon"
  showIconName="showIcon"
  showIconDefault={false}
/>
```

**Fields:**
- `buttonText`: TextField for button text content
- `buttonLink`: LinkField for href destination (can be hidden with `showButtonLink={false}`)
- `icon`: Icon field using Icon.ContentFields
- `showIcon`: Toggle for icon visibility

#### StyleFields.tsx

Configurable props for variant and icon position:

```tsx
<Button.StyleFields
  buttonVariantLabel="Button variant"
  buttonVariantName="buttonVariant"
  buttonVariantDefault="primary"
  buttonIconPositionLabel="Icon position"
  buttonIconPositionName="buttonIconPosition"
  buttonIconPositionDefault="right"
/>
```

**Fields:**
- `buttonVariant`: ChoiceField for selecting visual style (primary, secondary, tertiary)
- `buttonIconPosition`: ChoiceField for selecting icon placement (left, right). This field has a hardcoded visibility rule — it is only shown when the icon toggle is enabled (`iconComponentShowIcon === true`), which corresponds to the `BooleanField` id hardcoded in `Icon.ContentFields`.

### Module Usage Example

```tsx
import Button from '@hubspot/cms-component-library/Button';

export default function CTAModule({ fieldValues }) {
  return (
    <Button
      buttonType="link"
      variant={fieldValues.buttonVariant}
      href={fieldValues.buttonLink?.url?.href}
      target="_blank"
      rel="noopener noreferrer"
      showIcon={fieldValues.showIcon}
      iconFieldPath="icon"
      iconPosition="right"
    >
      {fieldValues.buttonText}
    </Button>
  );
}
```

## Styling

### CSS Variables

The Button component uses CSS variables for theming and customization:

**Base Styles:**
- `--hscl-button-gap`: Space between text and icon (default: 8px)
- `--hscl-button-backgroundColor`: Background color
- `--hscl-button-color`: Text color
- `--hscl-button-paddingBlock`: Vertical padding
- `--hscl-button-paddingInline`: Horizontal padding
- `--hscl-button-borderRadius`: Border radius
- `--hscl-button-borderWidth`: Border width
- `--hscl-button-borderColor`: Border color
- `--hscl-button-fontSize`: Font size
- `--hscl-button-fontWeight`: Font weight

**Hover States:**
- `--hscl-button-backgroundColor-hover`: Hover background color
- `--hscl-button-color-hover`: Hover text color
- `--hscl-button-borderWidth-hover`: Hover border width
- `--hscl-button-borderColor-hover`: Hover border color

**Focus States:**
- `--hscl-button-backgroundColor-focus`: Focus background color
- `--hscl-button-color-focus`: Focus text color
- `--hscl-button-borderWidth-focus`: Focus border width
- `--hscl-button-borderColor-focus`: Focus border color
- `--hscl-button-outlineWidth-focus`: Focus outline width
- `--hscl-button-outlineColor-focus`: Focus outline color
- `--hscl-button-outlineOffset-focus`: Focus outline offset

**Icon:**
- `--hscl-button-icon-fill`: Icon fill color

### Custom Styling Example

```tsx
<Button
  buttonType="button"
  variant="primary"
  style={{
    '--hscl-button-backgroundColor': '#FF7A59',
    '--hscl-button-color': '#FFFFFF',
    '--hscl-button-paddingBlock': '12px',
    '--hscl-button-paddingInline': '24px',
    '--hscl-button-borderRadius': '8px',
  }}
>
  Custom Colors
</Button>
```

## Accessibility

The Button component follows accessibility best practices:

- **Semantic HTML**: Renders appropriate elements (`<button>` or `<a>`) based on context
- **Keyboard Navigation**: Native keyboard support for both button and link variants
  - Buttons: Space and Enter keys activate
  - Links: Enter key navigates
- **Focus Management**: CSS-based focus styles with outline for keyboard users
- **Disabled State**:
  - Only available for `buttonType="button"`
  - Sets `disabled` attribute and reduces opacity
  - Prevents click events and shows not-allowed cursor
- **Icon Accessibility**:
  - `iconPurpose="SEMANTIC"`: Icon conveys meaning (includes accessible title)
  - `iconPurpose="DECORATIVE"`: Icon is visual only (aria-hidden)
  - `iconTitle` provides screen reader description for semantic icons
- **Link Security**:
  - Use `rel="noopener noreferrer"` with `target="_blank"` to prevent security vulnerabilities


## Best Practices

- **Choose the right type**: Use `buttonType="button"` for actions (submit, toggle, open modal) and `buttonType="link"` for navigation
- **Never use `<a>` for actions**: If it's not navigating to a URL, use `buttonType="button"`
- **Always use `rel="noopener noreferrer"` with `target="_blank"`**: Prevents security vulnerabilities with external links
- **Button type requires JavaScript islands**: Interactive buttons with `onClick` handlers only work in JavaScript islands, not in static HubSpot modules
- **Icon positioning**: Place icons at the end (right) for forward actions, at the start (left) for back/previous actions
- **Icon purpose**: Use `SEMANTIC` when the icon adds meaning, `DECORATIVE` when it's purely visual
- **Disabled state**: Only use with `buttonType="button"`, not applicable to links
- **CSS Variables**: Override design tokens using CSS variables rather than hardcoding values
- **Variant system**: Currently variants are passed as props but full theming implementation is pending

## Common Patterns

### Call-to-Action (CTA) Button

```tsx
<Button
  buttonType="link"
  variant="primary"
  href="/signup"
  showIcon={true}
  iconFieldPath="icon"
  iconPosition="right"
>
  Get Started
</Button>
```

### Form Submit Button

```tsx
<Button
  buttonType="button"
  variant="primary"
  onClick={handleSubmit}
  disabled={isSubmitting}
>
  {isSubmitting ? 'Submitting...' : 'Submit Form'}
</Button>
```

### Navigation Button with Icon

```tsx
<Button
  buttonType="link"
  variant="secondary"
  href="/dashboard"
  showIcon={true}
  iconFieldPath="icon"
  iconPosition="left"
>
  Back to Dashboard
</Button>
```

### External Resource Link

```tsx
<Button
  buttonType="link"
  variant="tertiary"
  href="https://docs.hubspot.com"
  target="_blank"
  rel="noopener noreferrer"
  showIcon={true}
  iconFieldPath="icon"
  iconPosition="right"
>
  View Documentation
</Button>
```

## Related Components

- **Icon**: Used internally for icon rendering. Can be used standalone for custom icon implementations.

