# List Component

A flexible list component that renders ordered (`<ol>`) or unordered (`<ul>`) lists with customizable spacing, variants, and optional icons for list items.

## Import path
```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';
```

## Purpose

The List component provides a consistent way to render lists in HubSpot CMS projects. It combines the semantic correctness of native HTML list elements with the flexibility of the Flex component for layout control. The component supports both ordered (numbered) and unordered (bulleted) lists, with an accompanying ListItem component that can display text with optional icons.

## Compositional Component Pattern

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

| Component | Role | Renders |
|-----------|------|---------|
| `List` | Container | `<ol>` or `<ul>` |
| `ListItem` | Child | `<li>` |

**Why this pattern?**
- **Separation of concerns**: List handles container semantics (ordered vs unordered, gap, variant), while ListItem handles individual item presentation (text, icons)
- **Flexibility**: ListItem can be extended or customized independently
- **HubSpot CMS integration**: Each component has its own field definitions, allowing RepeatedGroup usage for dynamic lists
- **Type safety**: Props are scoped to their respective components, preventing invalid configurations

**Key relationships:**
- ListItem should **always** be used inside a List component
- List passes layout context (gap, variant styling) to children via CSS
- ListItem handles its own icon resolution via `itemsFieldPath` and `index` props

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

## Component Structure

```
List/
├── index.tsx                     # Main List component with render logic
├── types.ts                      # TypeScript type definitions
├── ContentFields.tsx             # HubSpot field definitions for list type
├── StyleFields.tsx               # HubSpot field definitions for variant
├── index.module.scss             # CSS module for list styling
├── ListItem/
│   ├── index.tsx                 # ListItem component
│   ├── types.ts                  # ListItem TypeScript types
│   ├── ContentFields.tsx         # HubSpot field definitions for list items
│   └── index.module.scss         # CSS module for list item styling
└── stories/
    ├── List.stories.tsx          # Storybook examples
    ├── ListDecorator.tsx         # Storybook decorator
    └── ListDecorator.module.css  # Decorator styles
```

## Components

### List (Main Component)

**Purpose:** Container component that renders either an `<ol>` or `<ul>` element based on the `listType` prop, with Flex-based layout control.

**Props:**
```tsx
{
  listType?: 'ordered' | 'unordered';                     // List type - 'ordered' renders <ol>, 'unordered' renders <ul>
  variant?: 'primary' | 'secondary' | 'tertiary';         // Visual style variant
  gap?: string;                                           // Space between list items (any valid CSS length value, e.g., '16px', '1rem', '0')
  className?: string;                                     // Additional CSS classes
  style?: CSSVariables;                                   // Inline styles (including CSS custom properties)
  children?: React.ReactNode;                             // ListItem components
}
```

### ListItem (Child Component)

**Purpose:** Individual list item component that renders an `<li>` element with optional icon support (falls back to regular bullets or numbers when icons are disabled).

**Props:**
```tsx
{
  children?: React.ReactNode;                 // List item content (text, elements, etc.)
  index?: number;                             // Item index (for field path generation)
  itemsFieldPath?: string;                    // Parent field path for icon lookup
  iconName?: string;                          // Field name for icon (default: 'icon')
  iconSize?: number;                          // Icon size in pixels (default: 16)
  iconFill?: string;                          // Icon fill color
  showIcon?: boolean;                         // Toggle icon visibility (default: true)
  iconPurpose?: 'SEMANTIC' | 'DECORATIVE';    // Icon accessibility role (defaults to 'DECORATIVE')
  iconTitle?: string;                         // Icon title for screen readers
  className?: string;                         // Additional CSS classes
  style?: React.CSSProperties;                // Inline styles
}
```

## Usage Examples

### Basic Unordered List

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

<List listType="unordered" variant="primary">
  <ListItem showIcon={false}>First item</ListItem>
  <ListItem showIcon={false}>Second item</ListItem>
  <ListItem showIcon={false}>Third item</ListItem>
</List>
```

### Basic Ordered List

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

<List listType="ordered" variant="primary">
  <ListItem showIcon={false}>Step one</ListItem>
  <ListItem showIcon={false}>Step two</ListItem>
  <ListItem showIcon={false}>Step three</ListItem>
</List>
```

### List with Custom Gap

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

<List listType="unordered" variant="primary" gap="1rem">
  <ListItem showIcon={false}>Spaced item one</ListItem>
  <ListItem showIcon={false}>Spaced item two</ListItem>
  <ListItem showIcon={false}>Spaced item three</ListItem>
</List>
```

### List Items with Icons

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

<List listType="unordered" variant="primary">
  <ListItem
    showIcon={true}
    iconName="icon"
    iconSize={20}
    itemsFieldPath="items"
    index={0}
    iconPurpose="DECORATIVE"
  >
    Item with icon
  </ListItem>
  <ListItem
    showIcon={true}
    iconName="icon"
    iconSize={20}
    itemsFieldPath="items"
    index={1}
    iconPurpose="DECORATIVE"
  >
    Another item with icon
  </ListItem>
</List>
```

### With Custom Styling

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

<List
  listType="unordered"
  variant="primary"
  gap="8px"
  className="custom-list-class"
  style={{ maxWidth: '500px' }}
>
  <ListItem showIcon={false}>Custom styled item</ListItem>
</List>
```

## HubSpot CMS Integration

### Field Definitions

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

#### List.ContentFields

Configurable props for list type selection:

```tsx
<List.ContentFields
  listTypeName="listType"
  listTypeLabel="List type"
  listTypeDefault="unordered"
/>
```

**Fields:**
- `listType`: ChoiceField for selecting ordered or unordered list

#### List.StyleFields

Configurable props for variant selection:

```tsx
<List.StyleFields
  variantName="variant"
  variantLabel="Variant"
  variantDefault="primary"
/>
```

**Fields:**
- `variant`: ChoiceField for selecting visual style (primary, secondary, tertiary)

**Note:** Gap must be set directly via the `gap` prop on the List component, as there is no field definition for it in StyleFields.

#### ListItem.ContentFields

Configurable props for list item content:

```tsx
<ListItem.ContentFields
  textName="text"
  textLabel="Item text"
  textDefault="Add a list item here."
  iconName="icon"
  iconLabel="Icon"
  iconDefault={{ name: 'check', unicode: 'f00c', type: 'SOLID' }} // FontAwesome icon set
/>
```

**Fields:**
- `text`: TextField for list item text content
- `icon`: Icon field using Icon.ContentFields

### Module Usage Example

```tsx
import { ModuleMeta } from '../types/modules.js';
import List, { ListItem } from '@hubspot/cms-component-library/List';
import { GapValue } from '@hubspot/cms-component-library/List/types';

type FeatureListModuleProps = {
  listType?: 'ordered' | 'unordered';
  style?: {
    variant?: 'primary' | 'secondary' | 'tertiary';
    gap?: GapValue;
  };
  listItems?: Array<{
    text?: string;
  }>;
};

export const Component = ({
  listType = 'unordered',
  style,
  listItems = [],
}: FeatureListModuleProps) => {
  const variant = style?.variant ?? 'primary';
  const gap = style?.gap ?? '0px';

  return (
    <List
      listType={listType}
      variant={variant}
      gap={gap}
    >
      {listItems.map(({ text }, index) => (
        <ListItem
          key={index}
          index={index}
          itemsFieldPath="listItems"
          iconFill={`var(--hscl-listItem-iconColor-${variant})`}
        >
          {text}
        </ListItem>
      ))}
    </List>
  );
};

export const meta: ModuleMeta = {
  label: 'Feature List',
  content_types: [],
  icon: '',
  categories: ['text'],
};
```

### Module Fields Example

```tsx
import {
  FieldGroup,
  ModuleFields,
  RepeatedFieldGroup,
  TextField,
} from '@hubspot/cms-components/fields';
import List, { ListItem } from '@hubspot/cms-component-library/List';

const defaultItem = {
  text: 'Add a list item here.',
  icon: { name: 'check', unicode: 'f00c', type: 'SOLID' }, // FontAwesome icon set
};

export const fields = (
  <ModuleFields>
    <List.ContentFields />
    <RepeatedFieldGroup
      label="List items"
      name="listItems"
      occurrence={{ min: 1, max: 20, default: 4 }}
      default={[defaultItem, defaultItem, defaultItem, defaultItem]}
    >
      <ListItem.ContentFields />
    </RepeatedFieldGroup>
    <FieldGroup label="Style" name="style" tab="STYLE">
      <List.StyleFields
        variantName="variant"
        variantLabel="Variant"
        variantDefault="primary"
      />
      <TextField
        label="Gap"
        name="gap"
        default="0px"
        helpText="Space between list items (e.g., '0', '0.5rem', '16px')"
      />
    </FieldGroup>
  </ModuleFields>
);
```

## Styling

### CSS Variables

The List component uses CSS variables for theming and customization:

**List Item Text:**
- `--hscl-list-item-text-color`: Text color for list items (set via variant)
- `--hscl-listItem-textColor-primary`: Primary variant text color
- `--hscl-listItem-textColor-secondary`: Secondary variant text color
- `--hscl-listItem-textColor-tertiary`: Tertiary variant text color

**List Item Icon:**
- `--hscl-listItem-iconColor-primary`: Primary variant icon color
- `--hscl-listItem-iconColor-secondary`: Secondary variant icon color
- `--hscl-listItem-iconColor-tertiary`: Tertiary variant icon color

### Custom Styling Example

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

<List
  listType="unordered"
  variant="primary"
  style={{
    '--hscl-list-item-text-color': '#333333',
  }}
>
  <ListItem showIcon={false}>Custom colored item</ListItem>
</List>
```

### CSS Module Classes

**List (`index.module.scss`):**
- `.list`: Base list styles (removes default padding/margin, positions bullets inside)
- Nested `.list`: Indented styling for nested lists

**ListItem (`ListItem/index.module.scss`):**
- `.listItem`: Flex display for items with icons
- `.listItemDefault`: Standard list-item display for items without icons
- `.listItemContent`: Flex content wrapper

## Accessibility

The List component follows accessibility best practices:

- **Semantic HTML**: Renders appropriate elements (`<ol>` for ordered, `<ul>` for unordered)
- **List Semantics**: Proper `<li>` elements maintain screen reader list navigation
- **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
- **Keyboard Navigation**: Native list keyboard navigation is preserved
- **Content Structure**: Lists help screen reader users understand grouped content

## Best Practices

- **Choose the right list type**: Use `ordered` for sequential steps or rankings, `unordered` for non-sequential items
- **Icon field paths**: When using icons in dynamic lists, always provide `itemsFieldPath` and `index` to correctly resolve icon field paths
- **showIcon prop**: Set `showIcon={false}` to use default bullet/number styling, `showIcon={true}` for custom icons
- **Consistent variants**: Use the same variant across related lists for visual consistency
- **Gap selection**: Use any valid CSS length value (e.g., '0', '0.5rem', '1rem', '16px') for spacing between items
- **Dynamic rendering**: Always provide unique `key` props when mapping arrays to ListItems
- **CSS Variables**: Override design tokens using CSS variables rather than hardcoding values
- **Icon colors**: Use `iconFill` prop with variant-based CSS variables for consistent theming (e.g., `iconFill={`var(--hscl-listItem-iconColor-${variant})`}`)

## Common Patterns

### Feature List with Icons

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

const FeatureList = ({ features, variant = 'primary' }) => (
  <List listType="unordered" variant={variant} gap="0.5rem">
    {features.map((feature, index) => (
      <ListItem
        key={index}
        showIcon={true}
        iconName="icon"
        iconSize={20}
        itemsFieldPath="features"
        index={index}
        iconPurpose="DECORATIVE"
        iconFill={`var(--hscl-listItem-iconColor-${variant})`}
      >
        {feature.text}
      </ListItem>
    ))}
  </List>
);
```

### Step-by-Step Instructions

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

const StepList = ({ steps, variant = 'primary' }) => (
  <List listType="ordered" variant={variant} gap="1rem">
    {steps.map((step, index) => (
      <ListItem
        key={index}
        showIcon={false}
        index={index}
        itemsFieldPath="steps"
      >
        {step.text}
      </ListItem>
    ))}
  </List>
);
```

### Simple Text List

```tsx
import List, { ListItem } from '@hubspot/cms-component-library/List';

<List listType="unordered" variant="primary">
  <ListItem showIcon={false}>Simple item one</ListItem>
  <ListItem showIcon={false}>Simple item two</ListItem>
  <ListItem showIcon={false}>Simple item three</ListItem>
</List>
```

## Related Components

- **Flex**: Used internally for list layout control. The List component extends Flex capabilities.
- **Icon**: Used internally for rendering icons in ListItem. Can be used standalone for custom implementations.
