# Flip grid (goodtabs UI)

A grid that glides its items to their new places when you sort or filter them.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/flip-grid.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/flip-grid`

## Usage

```tsx
import { FlipGrid, FlipGridItem } from "@/components/ui/flip-grid"

<FlipGrid layoutKey={`${filter}-${sort}`}>
  {sorted.map((item) => (
    <FlipGridItem key={item.id} hidden={item.kind !== filter}>
      {item.name}
    </FlipGridItem>
  ))}
</FlipGrid>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| layoutKey | `string` |  | On FlipGrid. Change it whenever the order or filter changes, such as `${filter}-${sort}`. Required. |
| hidden | `boolean` | `false` | On FlipGridItem. Fades the item out and takes it out of the tab order. |

## When to use

- A gallery or catalogue of up to about 40 tiles with filters or a sort
- When keeping sight of a tile as it moves helps people follow the change
- Tiles of equal size, where every move is a pure translate

## When not to use

- Long lists or virtualised grids, because every item is measured
- Search results that change on each keystroke: swap them with no motion
- Tiles of mixed sizes, which stretch while they scale to fit

## Notes for agents

- GSAP installs from npm under GSAP's own licence. No GSAP code ships in this registry
- Keep every item mounted and pass hidden. An item you unmount has no exit, it just disappears
- Give each item a stable key, so React moves the same DOM node and Flip can follow it
- Under reduced motion the change is instant. Keep filter controls outside the grid so they hold focus

## The maths

- Stagger step is min(50ms, 300ms / n), so eight tiles start 37.5ms apart and the sweep stays under 300ms.
- Columns in the demo share one width, so each move is pure translation and the scale term stays at 1.

Docs: https://ui.goodtabs.co/components/flip-grid