---
title: Feature Grid
description: Responsive grid for feature cards
related:
  - /components/feature
  - /components/bento-grid
  - /components/grid
visibility: guest
draft: false
---

# Feature Grid

A responsive grid layout for displaying feature cards. Pairs with the Feature component.

It lays every feature out on the **same footing** — a uniform matrix of equal cards.
When your features are genuinely *unequal* — one headline capability, a few
supporting ones — reach for [bento grid](/components/bento-grid) instead: its cells
claim different amounts of space, so the eye gets a hierarchy rather than a grid.

## Basic Usage

:::preview{title="Feature grid with three columns"}
<x-wirekit::feature-grid cols="1 sm:2 lg:3">
    <x-wirekit::feature title="Fast">Built for speed and performance.</x-wirekit::feature>
    <x-wirekit::feature title="Flexible">Customize everything with design tokens.</x-wirekit::feature>
    <x-wirekit::feature title="Accessible">WCAG-compliant keyboard navigation.</x-wirekit::feature>
</x-wirekit::feature-grid>
:::

## Two Columns

:::preview{title="Two-column feature grid"}
<x-wirekit::feature-grid cols="1 sm:2">
    <x-wirekit::feature title="Open Source">MIT licensed, free forever.</x-wirekit::feature>
    <x-wirekit::feature title="Laravel Native">Built for Livewire and Blade.</x-wirekit::feature>
</x-wirekit::feature-grid>
:::

## With Icons

:::preview{title="Features with icons"}
<x-wirekit::feature-grid cols="1 sm:3">
    <x-wirekit::feature icon="edit" title="Easy Setup">Install and start building.</x-wirekit::feature>
    <x-wirekit::feature icon="check" title="Production Ready">Battle-tested components.</x-wirekit::feature>
    <x-wirekit::feature icon="close" title="No Lock-in">Eject anytime.</x-wirekit::feature>
</x-wirekit::feature-grid>
:::

## Cascading Stagger

Pair an entrance reveal on the children (or the grid wrapper) with `stagger` to make each card animate in with an incremental delay — produces a clean cascade instead of every card landing at once:

:::preview{title="Feature grid with 75ms stagger"}
<x-wirekit::feature-grid cols="1 sm:2 lg:3" stagger>
    <x-wirekit::feature animateIn="slide-up" icon="bolt" title="Fast" style="display: flex; flex-direction: column; align-items: center; text-align: center;">Built for speed.</x-wirekit::feature>
    <x-wirekit::feature animateIn="slide-up" icon="swatch" title="Flexible" style="display: flex; flex-direction: column; align-items: center; text-align: center;">Token-driven theming.</x-wirekit::feature>
    <x-wirekit::feature animateIn="slide-up" icon="check" title="Accessible" style="display: flex; flex-direction: column; align-items: center; text-align: center;">WCAG-compliant.</x-wirekit::feature>
</x-wirekit::feature-grid>
:::

`stagger` (boolean) uses the default 75ms step. Pass an integer for a custom rhythm:

```blade
<x-wirekit::feature-grid cols="1 sm:2 lg:3" :stagger="125">
    {{-- each child waits an additional 125ms before its entrance fires --}}
</x-wirekit::feature-grid>
```

Stagger uses CSS-only `:nth-child` rules — no JS — and caps at index 8 to avoid runaway delays on long lists. Honors `prefers-reduced-motion: reduce` (delays collapse to 0).

## Custom Stagger via CSS

The `stagger` prop emits a `.wk-stagger` class on the grid wrapper and sets `--wk-stagger-step` inline. You can also drive the stagger from CSS directly — useful when the step value depends on viewport size, external state, or a media query.

### CSS contract

| Selector | Effect |
|---|---|
| `.wk-stagger > *:nth-child(N)` | Each child gets `animation-delay: calc((N - 1) × var(--wk-stagger-step))`. |
| `--wk-stagger-step` | The per-child increment. Default `75ms` when emitted via the `stagger` prop. Overrideable per-instance via `style="--wk-stagger-step: …"` OR globally via `:root {}`. |
| Cap | `:nth-child(N)` rules cap at index 8 so the final visible delay stays under ~600 ms by default. |

### Example: viewport-relative step

:::preview{title="Custom --wk-stagger-step via inline style"}
<x-wirekit::feature-grid cols="1 sm:2 lg:3" stagger style="--wk-stagger-step: 200ms;">
    <x-wirekit::feature animateIn="slide-up" icon="bolt" title="Slow cascade" style="display: flex; flex-direction: column; align-items: center; text-align: center;">200ms per child.</x-wirekit::feature>
    <x-wirekit::feature animateIn="slide-up" icon="swatch" title="Slow cascade" style="display: flex; flex-direction: column; align-items: center; text-align: center;">Second child waits 200ms.</x-wirekit::feature>
    <x-wirekit::feature animateIn="slide-up" icon="check" title="Slow cascade" style="display: flex; flex-direction: column; align-items: center; text-align: center;">Third waits 400ms.</x-wirekit::feature>
</x-wirekit::feature-grid>
:::

```blade
{{-- Step scales with viewport — tighter cascade on phones, roomier on desktop --}}
<x-wirekit::feature-grid cols="1 sm:2 lg:3" stagger style="--wk-stagger-step: clamp(50ms, 1vw, 150ms)">
    {{-- … --}}
</x-wirekit::feature-grid>
```

Honors `prefers-reduced-motion: reduce` — every child's delay collapses to 0 inside the global reduced-motion block, regardless of the `--wk-stagger-step` value.

See [Public CSS API → wk-stagger](../extending/public-css-api.md#animation--motion) for the full contract + stability tier.

## Props

### Feature Grid

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `cols` | string\|int | `'1 sm:2 lg:3'` | Column configuration (responsive string or number) |
| `gap` | string | `'lg'` | Gap between items: `none`, `sm`, `md`, `lg`, `xl` |
| `stagger` | bool\|int\|null | `null` | When `true`, cascades child entrance animations at 75ms steps. Pass an integer to override the step (e.g. `:stagger="125"`). |
| `scope` | string\|null | `null` | Scoped personalization name |

### Feature

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `icon` | string\|null | `null` | Icon name for the feature |
| `title` | string\|null | `null` | Feature heading |
| `scope` | string\|null | `null` | Scoped personalization name |

**The rung names are shared with a second ladder, and the values are not.** `gap` reads `--space-wk-*`; the tighter `--gap-wk-*` ladder uses the same `xs`…`2xl` labels with different values from `md` up, and WireKit's own components read it for spacing inside a component. Swapping one for the other by name silently re-spaces the container — see [Two spacing ladders, same rung names](/theming/design-tokens#two-spacing-ladders-same-rung-names).

## Keyboard Interaction

This component is purely presentational and does not respond to keyboard input.

## Design Tokens

The Feature Grid is a layout-only wrapper — it composes child [Feature](/components/feature#design-tokens) entries inside a Tailwind grid layout (`grid-cols-{n}` per breakpoint). The wrapper itself does not reach for theme tokens; per-feature colors, icon chips, and typography come from the inner Feature component.
