# Accordion Component

A collapsible content component that creates expandable/collapsible sections using native HTML `<details>`/`<summary>` elements. It supports multiple style variants, icon options, and flexible content.

## Import path
```tsx
import Accordion, { AccordionItem, AccordionTitle, AccordionContent } from '@hubspot/cms-component-library/Accordion';
```

## Purpose

The Accordion component provides a consistent way to render collapsible content sections in HubSpot CMS projects. It leverages native HTML `<details>` and `<summary>` elements for built-in expand/collapse functionality without requiring JavaScript. The component supports multiple style variants, customizable expand/collapse icons, and can contain any content within the expandable panels.

## Compositional Component Pattern

The Accordion component follows a **parent/child compositional pattern**, consisting of four separate but related components:

| Component | Role | Renders |
|-----------|------|---------|
| `Accordion` | Container | Flex column layout |
| `AccordionItem` | Item wrapper | `<details>` |
| `AccordionTitle` | Clickable trigger | `<summary>` |
| `AccordionContent` | Expandable panel | `<div>` |

**Why this pattern?**
- **Separation of concerns**: Each component handles a specific responsibility (layout, state, trigger, content)
- **Native HTML semantics**: Uses `<details>`/`<summary>` for built-in accessibility and keyboard support
- **Flexibility**: Each subcomponent can be styled and customized independently
- **HubSpot CMS integration**: Each component has its own field definitions, allowing RepeatedGroup usage for dynamic accordions
- **Type safety**: Props are scoped to their respective components, preventing invalid configurations

**Key relationships:**
- `AccordionItem` should **always** contain both `AccordionTitle` and `AccordionContent`
- `AccordionItem` should **always** be used inside an `Accordion` component
- `AccordionItem` controls variant styling via CSS variables that cascade to child components
- `AccordionTitle` renders the clickable summary with configurable expand/collapse icons
- `AccordionContent` contains the expandable content that shows/hides

This pattern is distinct from the "Compound Component Pattern" (e.g., `AccordionItem.StyleFields`) which attaches field definitions—Accordion uses *both* patterns together.

## Component Structure

```
Accordion/
├── index.tsx                     # Main Accordion container component
├── types.ts                      # TypeScript type definitions for Accordion
├── AccordionItem/
│   ├── index.tsx                 # AccordionItem wrapper component
│   ├── types.ts                  # AccordionItem TypeScript types
│   ├── StyleFields.tsx           # HubSpot field definitions for variant
│   └── index.module.scss         # CSS module for item styling
├── AccordionTitle/
│   ├── index.tsx                 # AccordionTitle component
│   ├── types.ts                  # AccordionTitle TypeScript types
│   ├── ContentFields.tsx         # HubSpot field definitions for title/icon
│   ├── icons.tsx                 # SVG icon components (Chevron, Plus, Minus)
│   └── index.module.scss         # CSS module for title styling
├── AccordionContent/
│   ├── index.tsx                 # AccordionContent component
│   ├── types.ts                  # AccordionContent TypeScript types
│   ├── ContentFields.tsx         # HubSpot field definitions for content
│   └── index.module.scss         # CSS module for content styling
└── stories/
    ├── Accordion.stories.tsx     # Storybook examples
    └── AccordionDecorator.tsx    # Storybook decorator with variant styles
```

## Components

### Accordion (Main Container)

**Purpose:** Container component that provides vertical layout with configurable gap spacing between accordion items.

**Props:**
```tsx
{
  gap?: string;                    // Space between accordion items (default: '24px')
  className?: string;              // Additional CSS classes
  style?: React.CSSProperties;     // Inline styles
  children: React.ReactNode;       // AccordionItem components
}
```

### AccordionItem (Item Wrapper)

**Purpose:** Wrapper component that renders a `<details>` element, providing the expand/collapse container with variant styling.

**Props:**
```tsx
{
  variant?: 'variant1' | 'variant2' | 'variant3' | 'variant4';  // Visual style variant (default: 'variant1')
  className?: string;                                           // Additional CSS classes
  style?: React.CSSProperties;                                  // Inline styles
  children: React.ReactNode;                                    // Should contain AccordionTitle and AccordionContent
}
```

**Expected children:** Always include both `AccordionTitle` and `AccordionContent` as children.

### AccordionTitle (Trigger)

**Purpose:** Clickable trigger component that renders a `<summary>` element with text and an expand/collapse icon.

**Props:**
```tsx
{
  icon?: 'chevron' | 'plus' | 'caret';  // Icon type (default: 'chevron')
  className?: string;                   // Additional CSS classes
  style?: React.CSSProperties;          // Inline styles
  children?: React.ReactNode;           // Title text content
}
```

### AccordionContent (Panel)

**Purpose:** Content panel component that renders a `<div>` containing the expandable content.

**Props:**
```tsx
{
  className?: string;              // Additional CSS classes
  style?: React.CSSProperties;     // Inline styles
  children?: React.ReactNode;      // Any content (text, HTML, components)
}
```

## Usage Examples

### Basic Accordion

```tsx
import Accordion, { AccordionItem, AccordionTitle, AccordionContent } from '@hubspot/cms-component-library/Accordion';

<Accordion>
  <AccordionItem>
    <AccordionTitle>What is HubSpot?</AccordionTitle>
    <AccordionContent>
      <p>HubSpot is a leading CRM platform that provides software and support to help businesses grow better.</p>
    </AccordionContent>
  </AccordionItem>
  <AccordionItem>
    <AccordionTitle>How do I get started?</AccordionTitle>
    <AccordionContent>
      <p>Sign up for a free account and explore our comprehensive onboarding guides and tutorials.</p>
    </AccordionContent>
  </AccordionItem>
</Accordion>
```

### With Plus/Minus Icon

```tsx
import Accordion, { AccordionItem, AccordionTitle, AccordionContent } from '@hubspot/cms-component-library/Accordion';

<Accordion>
  <AccordionItem>
    <AccordionTitle icon="plus">Plus becomes minus when expanded</AccordionTitle>
    <AccordionContent>
      <p>The plus icon switches to a minus icon when expanded, clearly indicating toggle state.</p>
    </AccordionContent>
  </AccordionItem>
</Accordion>
```

### Dynamic Rendering from Array

```tsx
import Accordion, { AccordionItem, AccordionTitle, AccordionContent } from '@hubspot/cms-component-library/Accordion';

const faqs = [
  { question: 'What payment methods do you accept?', answer: 'We accept all major credit cards and PayPal.' },
  { question: 'Can I cancel anytime?', answer: 'Yes, you can cancel your subscription at any time.' },
  { question: 'Do you offer refunds?', answer: 'We offer a 30-day money-back guarantee.' },
];

<Accordion>
  {faqs.map(({ question, answer }, index) => (
    <AccordionItem key={index}>
      <AccordionTitle icon="plus">{question}</AccordionTitle>
      <AccordionContent>{answer}</AccordionContent>
    </AccordionItem>
  ))}
</Accordion>
```

### With Rich Content

```tsx
import Accordion, { AccordionItem, AccordionTitle, AccordionContent } from '@hubspot/cms-component-library/Accordion';

<Accordion>
  <AccordionItem>
    <AccordionTitle>Getting Started Guide</AccordionTitle>
    <AccordionContent>
      <p>Welcome to HubSpot! Here are the steps to get started:</p>
      <ol>
        <li>Complete your profile setup</li>
        <li>Connect your email and calendar</li>
        <li>Import your existing contacts</li>
        <li>Set up your first campaign</li>
      </ol>
      <p><strong>Pro tip:</strong> Start with our interactive tutorials.</p>
    </AccordionContent>
  </AccordionItem>
</Accordion>
```

## HubSpot CMS Integration

### Field Definitions

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

#### AccordionItem.StyleFields

Configurable props for variant selection:

```tsx
<AccordionItem.StyleFields
  variantName="variant"
  variantLabel="Variant"
  variantDefault="variant1"
/>
```

**Fields:**
- `variant`: ChoiceField for selecting visual style (variant1, variant2, variant3, variant4)

#### AccordionTitle.ContentFields

Configurable props for title text and icon:

```tsx
<AccordionTitle.ContentFields
  titleName="title"
  titleLabel="Title"
  titleDefault="Accordion Title"
  iconName="icon"
  iconLabel="Icon"
  iconDefault="chevron"
/>
```

**Fields:**
- `title`: TextField for accordion title text
- `icon`: ChoiceField for selecting icon type (caret, chevron, plus)

#### AccordionContent.ContentFields

Configurable props for content:

```tsx
<AccordionContent.ContentFields
  contentName="content"
  contentLabel="Content"
  contentDefault="<p>Accordion content goes here.</p>"
/>
```

**Fields:**
- `content`: RichTextField for accordion content

### Module Usage Example

```tsx
import { ModuleMeta } from '../types/modules.js';
import Accordion, {
  AccordionItem,
  AccordionTitle,
  AccordionContent,
} from '@hubspot/cms-component-library/Accordion';
import { AccordionVariant } from '@hubspot/cms-component-library/Accordion/AccordionItem/types';
import { AccordionIconType } from '@hubspot/cms-component-library/Accordion/AccordionTitle/types';

type FAQModuleProps = {
  style?: {
    variant?: AccordionVariant;
  };
  accordionItems?: Array<{
    title?: string;
    content?: string;
    icon?: AccordionIconType;
  }>;
};

export const Component = ({
  style,
  accordionItems = [],
}: FAQModuleProps) => {
  const variant = style?.variant;

  return (
    <Accordion>
      {accordionItems.map(({ title, content, icon }, index) => (
        <AccordionItem key={index} variant={variant}>
          <AccordionTitle icon={icon}>{title}</AccordionTitle>
          <AccordionContent>{content}</AccordionContent>
        </AccordionItem>
      ))}
    </Accordion>
  );
};

export const meta: ModuleMeta = {
  label: 'FAQ Accordion',
  content_types: [],
  icon: '',
  categories: ['body_content'],
};
```

### Module Fields Example

```tsx
import {
  FieldGroup,
  ModuleFields,
  RepeatedFieldGroup,
} from '@hubspot/cms-components/fields';
import {
  AccordionContent,
  AccordionItem,
  AccordionTitle,
} from '@hubspot/cms-component-library/Accordion';

const defaultItem = {
  title: 'Accordion Title',
  content: '<p>Accordion content goes here. You can add multiple lines of text.</p>',
  icon: 'chevron',
};

export const fields = (
  <ModuleFields>
    <RepeatedFieldGroup
      label="Accordion Items"
      name="accordionItems"
      occurrence={{ min: 1, max: 20, default: 3 }}
      default={[defaultItem, defaultItem, defaultItem]}
    >
      <AccordionTitle.ContentFields />
      <AccordionContent.ContentFields />
    </RepeatedFieldGroup>
    <FieldGroup label="Style" name="style" tab="STYLE">
      <AccordionItem.StyleFields />
    </FieldGroup>
  </ModuleFields>
);
```

## Styling

### CSS Variables

The Accordion component uses CSS variables for theming and customization. Variables are organized by variant for consistent styling across the component.

**Per-Variant Variables (replace `{variant}` with variant1, variant2, variant3, or variant4):**

| Variable | Description | Default |
|----------|-------------|---------|
| `--hscl-accordion-{variant}-borderColor` | Border color | `#e0e0e0` |
| `--hscl-accordion-{variant}-borderRadius` | Border radius | `4px` |
| `--hscl-accordion-{variant}-borderThickness` | Border width | `1px` |
| `--hscl-accordion-{variant}-backgroundColor` | Background color | `transparent` |
| `--hscl-accordion-{variant}-textColor` | Text color | `#33475b` |
| `--hscl-accordion-{variant}-icon-fillColor` | Icon fill color | `#33475b` |

**Title-Specific Variables:**

| Variable | Description | Default |
|----------|-------------|---------|
| `--hscl-accordion-title-paddingBlock` | Vertical padding | `16px` |
| `--hscl-accordion-title-paddingInline` | Horizontal padding | `20px` |
| `--hscl-accordion-title-backgroundColor` | Title background | `transparent` |
| `--hscl-accordion-title-fontSize` | Title font size | `24px` |
| `--hscl-accordion-title-fontWeight` | Title font weight | `600` |
| `--hscl-accordion-title-textMarginEnd` | Space before icon | `16px` |

**Content-Specific Variables:**

| Variable | Description | Default |
|----------|-------------|---------|
| `--hscl-accordion-body-paddingBlock` | Vertical padding | `16px` |
| `--hscl-accordion-body-paddingInline` | Horizontal padding | `20px` |
| `--hscl-accordion-body-color` | Content text color | `inherit` |
| `--hscl-accordion-body-fontSize` | Content font size | `16px` |
| `--hscl-accordion-body-lineHeight` | Content line height | `1.5` |

### CSS Module Classes

**AccordionItem (`AccordionItem/index.module.scss`):**
- `.accordionItem`: Base details element styling with border, radius, background

**AccordionTitle (`AccordionTitle/index.module.scss`):**
- `.accordionTitle`: Flex container for title and icon
- `.accordionTitleText`: Title text with flex grow
- `.accordionIcon`: Base icon styling
- `.accordionIconChevron`: Chevron-specific sizing (rotates 180° when open)
- `.accordionIconPlus`: Plus icon (hidden when open)
- `.accordionIconMinus`: Minus icon (shown when open)
- `.accordionIconCaret`: Caret icon (rotates 180° when open)

**AccordionContent (`AccordionContent/index.module.scss`):**
- `.accordionContent`: Content area with padding and typography

## Accessibility

The Accordion component follows accessibility best practices:

- **Semantic HTML**: Uses native `<details>` and `<summary>` elements for built-in accessibility support
- **Keyboard Navigation**:
  - `Enter` or `Space` on summary toggles the accordion
  - Tab navigation works natively between accordion items
- **Screen Reader Support**:
  - `<details>` element announces expanded/collapsed state
  - `<summary>` element is announced as a button
- **Icon Accessibility**:
  - All icons have `aria-hidden="true"` since they are decorative
  - Icons have `role="img"` for proper semantics
- **Focus States**: Native focus styles are preserved for keyboard users
- **No JavaScript Required**: Expand/collapse functionality works without JavaScript

## Best Practices

- **Choose appropriate icons**: Use `caret` for a compact filled triangle indicator, `chevron` for subtle indication, `plus` for clearer expand/collapse semantics (common in FAQs)
- **Consistent variants**: Apply the same variant to all items within an accordion for visual consistency
- **Gap selection**: Use any valid CSS length value (e.g., '8px', '16px', '24px', '48px') for spacing between items
- **Dynamic rendering**: Always provide unique `key` props when mapping arrays to AccordionItems
- **Rich content**: AccordionContent supports any HTML content including lists, paragraphs, images, and nested components
- **Prefer library components**: When adding content inside AccordionContent, prefer using library components (e.g., `List`, `Heading`) over raw HTML elements for consistent theming and styling
- **CSS Variables**: Override design tokens using CSS variables rather than hardcoding values
- **Single responsibility**: Keep each accordion item focused on one topic for better UX

## Related Components

- **Flex**: Used internally for Accordion container layout. The Accordion component wraps Flex with a column direction.

