# Grid Component

A layout container component that implements the CSS Grid API for creating structured, two-dimensional layouts. Works with GridItem children for precise grid placement control.

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

## Purpose

The Grid component provides a consistent interface for creating grid-based layouts in HubSpot CMS projects. It solves the challenge of building complex two-dimensional layouts by abstracting CSS grid properties into a declarative component API. Developers should use this component when they need precise control over both rows and columns, such as dashboards, card galleries, magazine layouts, or any structured grid system. The component supports all essential grid properties through props, includes responsive breakpoints, and allows customization via semantic HTML elements.

## Quick Start Guide

### Basic Usage Pattern
```tsx
import Grid, { GridItem } from '@hubspot/cms-component-library/Grid';

// Simple grid - plain children
<Grid templateColumns="repeat(3, 1fr)" gap="16px">
  <div>Auto-placed item</div>
  <div>Auto-placed item</div>
</Grid>

// Advanced grid - GridItem for positioning
<Grid templateColumns="repeat(3, 1fr)" gap="16px">
  <GridItem gridColumn="span 2">Spans 2 columns</GridItem>
  <GridItem>Normal item</GridItem>
</Grid>

// GridItem with components
<Grid templateColumns="repeat(2, 1fr)" gap="16px">
  <GridItem as={Button} buttonType="primary">
    Button in grid
  </GridItem>
</Grid>
```

### Critical Rules
1. **Use props, not CSS**: `<GridItem gridColumn="1 / 3">` instead of `<div style={{ gridColumn: '1 / 3' }}>`
2. **GridItem for positioning**: Use GridItem when you need `gridColumn`, `gridRow`, `alignSelf`, `justifySelf`, or component rendering
3. **Mobile-first responsive**: Base props for mobile, then `*Md` (768px+) and `*Lg` (1024px+) variants
4. **`as` prop for components**: `<GridItem as={Button}>` passes through all Button props while adding grid positioning

## Component Structure

```
Grid/
├── index.tsx                     # Main Grid component with grid logic
├── types.ts                      # TypeScript type definitions for Grid props
├── index.module.scss             # CSS module with responsive design tokens
├── GridItem/
│   ├── index.tsx                 # GridItem component for child positioning
│   ├── types.ts                  # TypeScript type definitions for GridItem props
│   └── index.module.scss         # GridItem CSS module
└── stories/
    ├── Grid.stories.tsx          # Component usage examples
    ├── GridDecorator.tsx         # Storybook decorator
    └── GridDecorator.module.css  # Decorator styles
```

## Components

### Grid (Main Component)

**Purpose:** Creates a grid container that controls the two-dimensional layout, alignment, and spacing of child elements across rows and columns.

**Key Feature:** The `as` prop allows Grid to render as any semantic HTML element, maintaining grid functionality while improving document structure and accessibility.

**Props:**
```tsx
{
  as?: 'div' | 'span' | 'section' | 'article' | 'aside' | 'nav' | 'header' | 'footer' | 'main' | 'ul' | 'ol';  // HTML element type (default: 'div')
  templateColumns?: string;  // Grid template columns (e.g., 'repeat(3, 1fr)', '200px 1fr 1fr')
  templateColumnsMd?: string;  // Grid template columns at tablet breakpoint (768px+)
  templateColumnsLg?: string;  // Grid template columns at desktop breakpoint (1024px+)
  templateRows?: string;  // Grid template rows (e.g., 'repeat(2, 100px)', 'auto 1fr auto')
  templateRowsMd?: string;  // Grid template rows at tablet breakpoint (768px+)
  templateRowsLg?: string;  // Grid template rows at desktop breakpoint (1024px+)
  autoFlow?: 'row' | 'column' | 'row dense' | 'column dense';  // Grid auto flow direction (default: 'row')
  autoFlowMd?: 'row' | 'column' | 'row dense' | 'column dense';  // Grid auto flow at tablet breakpoint
  autoFlowLg?: 'row' | 'column' | 'row dense' | 'column dense';  // Grid auto flow at desktop breakpoint
  autoColumns?: string;  // Size of auto-generated columns (e.g., 'minmax(100px, auto)')
  autoRows?: string;  // Size of auto-generated rows (e.g., 'minmax(100px, auto)')
  justifyContent?: 'start' | 'end' | 'center' | 'stretch' | 'space-between' | 'space-around' | 'space-evenly';  // Grid horizontal alignment (default: 'stretch')
  justifyContentMd?: 'start' | 'end' | 'center' | 'stretch' | 'space-between' | 'space-around' | 'space-evenly';  // Grid horizontal alignment at tablet breakpoint
  justifyContentLg?: 'start' | 'end' | 'center' | 'stretch' | 'space-between' | 'space-around' | 'space-evenly';  // Grid horizontal alignment at desktop breakpoint
  alignItems?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Grid vertical alignment (default: 'stretch')
  alignItemsMd?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Grid vertical alignment at tablet breakpoint
  alignItemsLg?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Grid vertical alignment at desktop breakpoint
  gap?: string;  // Spacing between grid items (e.g., '16px', '1rem')
  gapMd?: string;  // Spacing between grid items at tablet breakpoint
  gapLg?: string;  // Spacing between grid items at desktop breakpoint
  paddingInline?: string;  // Horizontal padding
  paddingBlock?: string;  // Vertical padding
  marginInline?: string;  // Horizontal margin
  marginBlock?: string;  // Vertical margin
  maxWidth?: string;  // Maximum width constraint
  maxHeight?: string;  // Maximum height constraint
  inline?: boolean;  // Use inline-grid instead of grid (default: false)
  className?: string;  // Additional CSS classes
  style?: React.CSSProperties;  // Inline styles (including grid-specific child styles)
  children?: React.ReactNode;  // Child elements
}
```

### GridItem (Child Component)

**Purpose:** Wraps grid children to control their precise placement, spanning, and alignment within the Grid container. Can render as any HTML element or custom React component while maintaining grid positioning control.

**Key Feature:** The `as` prop is polymorphic - it accepts both HTML element strings ('div', 'section', etc.) and React component references (Button, Text, custom components). GridItem handles grid placement while passing through all other props to the underlying component.

**Props:**
```tsx
{
  as?: React.ElementType;  // Any HTML element or React component (default: 'div')
                            // Examples: 'div', 'article', Button, Text, CustomComponent
  gridColumn?: string;  // Grid column placement (e.g., '1 / 3', 'span 2', '2')
  gridColumnMd?: string;  // Grid column placement at tablet breakpoint (768px+)
  gridColumnLg?: string;  // Grid column placement at desktop breakpoint (1024px+)
  gridRow?: string;  // Grid row placement (e.g., '1 / 3', 'span 2', '2')
  gridRowMd?: string;  // Grid row placement at tablet breakpoint (768px+)
  gridRowLg?: string;  // Grid row placement at desktop breakpoint (1024px+)
  justifySelf?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Horizontal self-alignment
  justifySelfMd?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Horizontal self-alignment at tablet
  justifySelfLg?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Horizontal self-alignment at desktop
  alignSelf?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Vertical self-alignment
  alignSelfMd?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Vertical self-alignment at tablet
  alignSelfLg?: 'start' | 'end' | 'center' | 'stretch' | 'baseline';  // Vertical self-alignment at desktop
  className?: string;  // Additional CSS classes
  style?: React.CSSProperties;  // Inline styles
  children?: React.ReactNode;  // Child elements
  ...rest  // All props of the component specified in 'as' are passed through
}
```

**How the `as` Prop Works:**

GridItem's `as` prop provides flexibility in rendering while maintaining grid control:

1. **HTML Elements**: Pass element names as strings
   ```tsx
   <GridItem as="article">Content</GridItem>
   <GridItem as="section">Section content</GridItem>
   ```

2. **React Components**: Pass component references directly
   ```tsx
   <GridItem as={Button} buttonType="primary">Click me</GridItem>
   <GridItem as={Text} fieldPath="title" />
   ```

3. **Prop Pass-Through**: All props beyond GridItem's own props are forwarded to the underlying component
   ```tsx
   {/* Button-specific props are passed through */}
   <GridItem as={Button} href="https://example.com" buttonType="link">
     Link Button
   </GridItem>

   {/* Text-specific props are passed through */}
   <GridItem as={Text} fieldPath="sectionTitle" className="custom-text" />
   ```

4. **Grid Positioning**: GridItem handles all grid-specific positioning regardless of the underlying component
   ```tsx
   <GridItem
     as={Button}
     gridColumn="1 / 3"
     gridRow="2"
     buttonType="primary"
   >
     Positioned Button
   </GridItem>
   ```

## Usage Examples

**IMPORTANT: Always use Grid and GridItem props for layout control. Custom CSS should be a last resort only when props cannot achieve the desired layout.**

### Basic Grid with GridItem Placement

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

<Grid templateColumns="repeat(3, 1fr)" gap="16px">
  <GridItem>Item 1</GridItem>
  <GridItem>Item 2</GridItem>
  <GridItem gridColumn="span 2">Item 3 (spans 2 columns)</GridItem>
  <GridItem>Item 4</GridItem>
  <GridItem>Item 5</GridItem>
</Grid>
```

### GridItem with Components (using `as` prop)

```tsx
import Grid, { GridItem } from '@hubspot/cms-component-library/Grid';
import Button from '@hubspot/cms-component-library/Button';
import Text from '@hubspot/cms-component-library/Text';

<Grid templateColumns="repeat(2, 1fr)" gap="16px">
  {/* GridItem rendering as Button */}
  <GridItem
    as={Button}
    buttonType="primary"
    href="https://example.com"
  >
    Click Me
  </GridItem>

  {/* GridItem rendering as Text (heading feature set) */}
  <GridItem>
    <Text fieldPath="sectionTitle" />
  </GridItem>

  {/* Regular content */}
  <GridItem gridColumn="span 2">
    <p>Content spanning both columns</p>
  </GridItem>
</Grid>
```

### Responsive Grid Layout with GridItem

```tsx
{/* Use props for responsive behavior - NO custom CSS needed */}
<Grid
  templateColumns="1fr"
  templateColumnsMd="repeat(2, 1fr)"
  templateColumnsLg="repeat(3, 1fr)"
  gap="16px"
>
  <GridItem>Item 1</GridItem>
  <GridItem>Item 2</GridItem>
  <GridItem>Item 3</GridItem>
  <GridItem
    gridColumn="1"
    gridColumnMd="span 2"
    gridColumnLg="1"
  >
    Item 4 (spans 2 cols on tablet only)
  </GridItem>
  <GridItem>Item 5</GridItem>
  <GridItem>Item 6</GridItem>
</Grid>
```

### Complex Layout Using Props (NO custom CSS)

```tsx
import Grid, { GridItem } from '@hubspot/cms-component-library/Grid';
import Text from '@hubspot/cms-component-library/Text';

{/* Dashboard layout - all positioning via props */}
<Grid
  templateColumns="1fr"
  templateColumnsMd="200px 1fr"
  templateRows="auto 1fr auto"
  gap="16px"
>
  {/* Header - full width on all breakpoints */}
  <GridItem
    gridColumn="1"
    gridColumnMd="1 / -1"
  >
    <Text fieldPath="dashboardTitle" />
  </GridItem>

  {/* Sidebar - hidden on mobile, shown on tablet+ */}
  <GridItem
    gridColumn="1"
    gridRow="2"
    style={{ display: 'none' }}
    className="show-md"
  >
    Sidebar Navigation
  </GridItem>

  {/* Main content */}
  <GridItem
    gridColumn="1"
    gridColumnMd="2"
    gridRow="2"
  >
    Main Content Area
  </GridItem>

  {/* Footer - full width */}
  <GridItem
    gridColumn="1"
    gridColumnMd="1 / -1"
  >
    Footer Content
  </GridItem>
</Grid>
```

### Overlapping Items with GridItem

```tsx
{/* Create overlapping grid items using props */}
<Grid
  templateColumns="repeat(3, 1fr)"
  templateRows="repeat(2, 200px)"
  gap="16px"
>
  <GridItem
    gridColumn="1 / 3"
    gridRow="1 / 2"
  >
    Item 1 (columns 1-2)
  </GridItem>

  <GridItem
    gridColumn="2 / 4"
    gridRow="1 / 2"
  >
    Item 2 (columns 2-3, overlaps with Item 1)
  </GridItem>

  <GridItem
    as={Button}
    buttonType="link"
    href="https://example.com"
    gridColumn="3 / 4"
    gridRow="1 / 3"
  >
    Button spanning full height
  </GridItem>
</Grid>
```

### Auto-Fit Responsive Cards

```tsx
{/* GridItem optional for simple auto-placement */}
<Grid
  templateColumns="repeat(auto-fit, minmax(250px, 1fr))"
  gap="24px"
>
  <GridItem>Card 1</GridItem>
  <GridItem>Card 2</GridItem>
  <GridItem>Card 3</GridItem>
  <GridItem>Card 4</GridItem>
</Grid>
```

### Magazine Layout with GridItem Spanning

```tsx
{/* Use GridItem props instead of inline styles */}
<Grid
  templateColumns="repeat(4, 1fr)"
  templateRows="repeat(2, 150px)"
  gap="16px"
>
  <GridItem gridColumn="span 2" gridRow="span 2">
    Featured Article
  </GridItem>
  <GridItem>Article 2</GridItem>
  <GridItem>Article 3</GridItem>
  <GridItem>Article 4</GridItem>
  <GridItem>Article 5</GridItem>
</Grid>
```

### Semantic Section Layout with GridItem

```tsx
<Grid
  as="section"
  templateColumns="1fr 2fr"
  gap="32px"
  maxWidth="1200px"
  marginInline="auto"
>
  <GridItem as="aside">Sidebar Content</GridItem>
  <GridItem as="article">Main Article Content</GridItem>
</Grid>
```


### Item-Specific Alignment with GridItem

```tsx
<Grid
  templateColumns="repeat(3, 1fr)"
  templateRows="repeat(2, 150px)"
  gap="16px"
  alignItems="stretch"
>
  {/* Override grid-level alignment per item using props */}
  <GridItem alignSelf="start">
    Aligned to start
  </GridItem>

  <GridItem alignSelf="center" justifySelf="center">
    Centered both ways
  </GridItem>

  <GridItem alignSelf="end" justifySelf="end">
    Aligned to end
  </GridItem>

  <GridItem gridColumn="span 3" alignSelf="center">
    Spans all columns, centered vertically
  </GridItem>
</Grid>
```

## Accessibility

The Grid component supports accessibility best practices:

- **Semantic HTML**: The `as` prop allows rendering with appropriate semantic elements (nav, article, section, etc.) for better document structure and screen reader support
- **Keyboard Navigation**: Does not interfere with native keyboard navigation of child elements
- **Responsive Design**: Built-in responsive breakpoints ensure layouts adapt to different screen sizes and devices
- **Visual Order**: Grid placement allows visual reordering without changing DOM order, but be cautious that visual order should match reading order for accessibility

## Best Practices

### Layout Control Strategy
- **ALWAYS prefer props over custom CSS**: Grid and GridItem provide props for nearly all layout needs. Only resort to custom CSS when props truly cannot achieve the desired result.
- **Use GridItem for positioning**: Wrap children in GridItem when you need to control placement (`gridColumn`, `gridRow`), spanning, or individual alignment (`alignSelf`, `justifySelf`)
- **Direct children for simple grids**: Plain children are fine when items auto-flow without special positioning needs
- **Avoid inline styles for grid properties**: Instead of `style={{ gridColumn: '1 / 3' }}`, use `<GridItem gridColumn="1 / 3">`

### Component Usage
- **Choose semantic elements**: Use the `as` prop on both Grid and GridItem to render appropriate HTML elements (e.g., `as="section"` for content sections, `as="article"` for articles)
- **Leverage GridItem's `as` prop for components**: Use `<GridItem as={Button}>` instead of wrapping: `<GridItem><Button /></GridItem>`
- **Pass through component props**: When using `as={Component}`, GridItem forwards all non-grid props to the component

### Spacing and Sizing
- **Use gap instead of margins**: The `gap` property provides consistent spacing between grid items without margin collapsing issues
- **Leverage responsive props**: Use breakpoint variants (`templateColumnsMd`, `gridColumnMd`, etc.) to create mobile-first responsive layouts
- **Use fr units for flexibility**: The `fr` unit distributes available space proportionally (e.g., `1fr 2fr` creates a 1:2 ratio)
- **Combine with maxWidth**: Set `maxWidth` with `marginInline="auto"` for centered, constrained layouts

### Responsive Design
- **Mobile-first approach**: Define base props for mobile, then override with `*Md` and `*Lg` variants
- **Use auto-fit for fluid grids**: The pattern `repeat(auto-fit, minmax(250px, 1fr))` creates grids that automatically adjust column count
- **Responsive item placement**: Use `gridColumnMd` and `gridColumnLg` on GridItem to change placement at different breakpoints

### Alignment
- **Start with stretch alignment**: The default `alignItems="stretch"` and `justifyContent="stretch"` create consistent sizing
- **Override per item when needed**: Use GridItem's `alignSelf` and `justifySelf` props to override grid-level alignment for specific items

### Performance and Maintenance
- **Be mindful of dense packing**: Use `autoFlow="row dense"` or `autoFlow="column dense"` carefully, as it can create confusing visual order
- **Keep it simple**: Don't over-engineer grid structures. Use the simplest prop combination that achieves your layout

## Flex vs Grid: When to Use Which

**Use Grid when:**
- You need a two-dimensional layout (rows and columns together)
- You want precise control over item placement in both dimensions
- Creating structured layouts like galleries, dashboards, card grids, or forms
- You need items to align both horizontally and vertically in a predictable grid structure

**Use Flex when:**
- You need a one-dimensional layout (either a row or column)
- Content size should determine item dimensions
- You want simple alignment and spacing between items
- Items should automatically adjust based on available space

**Quick rule:** If you need both rows and columns working together in a structured layout, use Grid. If your layout is primarily linear (items in a row or stacked vertically), use Flex.

## Summary: Key Takeaways

1. **Props Over CSS**: Always use Grid and GridItem props for layout control. Custom CSS is a last resort.

2. **GridItem for Control**: Wrap children in GridItem when you need positioning, spanning, or per-item alignment.

3. **Polymorphic `as` Prop**: Both Grid and GridItem can render as any element or component while maintaining grid functionality.

4. **Prop Pass-Through**: GridItem forwards all non-grid props to the underlying component, enabling clean integration with library components.

5. **Mobile-First Responsive**: Define base props for mobile, then use `*Md` and `*Lg` variants for larger screens.

6. **Semantic HTML**: Use the `as` prop to improve document structure and accessibility.

7. **Keep It Simple**: Don't over-engineer. Use the simplest prop combination that achieves your layout.

## Related Components

- **Flex**: Use for one-dimensional layouts when you don't need both row and column control
- **GridItem**: Child component for precise grid placement and positioning
