# Crop area

> [llms.txt](https://zriz.dev/llms.txt)

`Area` is the crop you keep. `Handle` resizes it and `Grid` draws guides while you work.

The page at https\://zriz.dev/docs/crop-area runs this cropper: a 3:2 photo with eight handles and a grid on the crop, and open, reset and download in the corners.

## Anatomy

`Area` goes in `Viewport`. `Grid` and the handles go inside it:

```tsx
<Cropper.Area aria-label="Crop area">
  <Cropper.Grid />
  <Cropper.Handle position="top-left" />
  <Cropper.Handle position="top" />
  <Cropper.Handle position="top-right" />
  <Cropper.Handle position="right" />
  <Cropper.Handle position="bottom-right" />
  <Cropper.Handle position="bottom" />
  <Cropper.Handle position="bottom-left" />
  <Cropper.Handle position="left" />
</Cropper.Area>
```

Leave out the handles you do not need. With `shape="circle"`, the stylesheet hides the four corner handles.

`Area` points `aria-describedby` at the `Instructions` part. Render it with your own help text. Without it, the reference points at nothing and screen readers skip it. [Accessibility](https://zriz.dev/docs/accessibility.md) covers it and `Announcer`.

The demo above uses the styles from the zriz site.

## Recolour the focus ring

The stylesheet draws a two-tone ring inside `Area` on keyboard focus, so a crop flush with the viewport keeps it. Without the stylesheet, the browser draws its default ring. To recolour it:

```css
[data-zriz-item="area"]:focus-visible {
  outline-color: #000;
}
[data-zriz-item="area"]:focus-visible::after {
  outline-color: #fdca00;
}
```

## Make the handles easier to grab

Each handle's hit box is 44 px square, centred on the crop's edge. Set `--zriz-handle-size` on `Area` to change all eight. Give the viewport padding of at least half that size, or the clip cuts the box, see [viewport](https://zriz.dev/docs/viewport.md):

```css
[data-zriz-item="viewport"] {
  padding: 28px;
}
[data-zriz-item="area"] {
  --zriz-handle-size: 56px;
}
```

## Know when the grid shows

The grid hides at rest. It shows thirds (3 × 3) from the moment you press or move the crop, and a fine grid (9 × 9) while the dial moves:

| When | What shows |
| - | - |
| Press or move the crop | The thirds grid fades in, even if a press never moves. A drag, pinch, twist, wheel, handle, `Zoom` or a `useZoom` slider counts |
| Drag the dial or press a key on it | The fine grid fades in once the angle moves. A press that stays still shows none |
| Press a key on `Area` or `Zoom` | No new grid. A grid that already shows stays |
| Let go or stop moving the crop | It stays for a short hold, then fades out, see [accessibility](https://zriz.dev/docs/accessibility.md) |
| Let go of the dial | The fine grid fades out at once, or when a flick's glide stops |

## Make the straighten grid fainter

Lines of the fine grid carry no `data-coarse`. A fading grid keeps its lines, so this rule holds until the grid is gone:

```css
[data-zriz-item="grid"] > :not([data-coarse]) {
  background: rgb(255 255 255 / 0.3);
}
```

## Keyboard

These keys work while `Area` has focus, never on the window:

| Key | What it does |
| - | - |
| `arrow keys` | Move the crop by 1% of its size |
| `shift` + `arrow keys` | Move it by 10% |
| `alt` + `arrow keys` | Resize the crop by 1%, or 10% with Shift. Right and down grow it, left and up shrink it. A locked aspect keeps its ratio. A free crop changes that side only, and stops at the photo edge, `minSize`, `maxZoom` or 88 px on screen. The centre stays put |
| `+` or `=` | Zoom in 1.1× |
| `-` or `_` | Zoom out 1.1× |
| `0` | Jump back to where `Reset` goes, with no spring |

Escape during a handle drag cancels it and puts the crop back.

## API

### `Area`

Renders a `<div role="application">` inside `Viewport`, with `tabIndex={0}` once a photo is placed and `tabIndex={-1}` until then, so tab skips an empty crop. zriz writes its position and size inline on every frame. Every part also takes `className`, `render` and the props of its element, see [composition](https://zriz.dev/docs/composition.md). `className` and `render` get `{ shape, interacting }`.

- `aria-label` `string`

  Names the crop for screen readers, such as `"Crop area"`. Development builds warn without it
- `liveVariables` `boolean` = `false`

  Writes the variables below on `Area` every frame

| Attribute | When |
| - | - |
| `data-shape` | `"rect"` or `"circle"`, from `Root` |
| `data-visible` | While a photo is placed |
| `data-interacting` | During a gesture, and while a zriz key is held down |

| Variable | What it sets |
| - | - |
| `--zriz-frame` | Paints the frame and the handle marks, `#fff` by default. [Styling](https://zriz.dev/docs/styling.md) lists every colour |
| `--zriz-rotation` | With `liveVariables`, the straighten angle in degrees, like −4.5 |
| `--zriz-rotation-progress` | With `liveVariables`, the angle over its limit, from −1 to 1 |
| `--zriz-zoom` | With `liveVariables`, the zoom, 1 to `maxZoom` |
| `--zriz-zoom-progress` | With `liveVariables`, the zoom on a log scale, 0 to 1 |
| `--zriz-overscroll` | With `liveVariables`, how far in px a drag pulls the photo past an edge. 0 at rest |

### `Handle`

Renders an `aria-hidden` `<div>` inside `Area`, so a `render` element must not take focus. A drag stops at the photo edge, the viewport's padding and `maxZoom`. Each side also stops at 88 px on screen or `minSize`, whichever is larger. A side already smaller stays put and can only grow. The stylesheet hides the corner handles on a circle only when they sit right inside `Area`. `className` and `render` get `{ position, active }`.

- `position` `HandleProps["position"]` required

  The corner or edge it drags: `"top-left"`, `"top"`, `"top-right"`, `"right"`, `"bottom-right"`, `"bottom"`, `"bottom-left"`, `"left"`

| Attribute | When |
| - | - |
| `data-edge` | Always, set to its position |
| `data-active` | From a press on this handle until the pointer lets go, even if it never moves |

| Variable | What it sets |
| - | - |
| `--zriz-handle-size` | The hit box, 44 px square unless you set it |

### `Grid`

Renders an `aria-hidden` `<div>` of `<span>` lines inside `Area`. It has no props of its own. The stylesheet gives each line 1 px. Without it, set `min-width` and `min-height` yourself. `className` and `render` get `{ grid }`.

| Attribute | When |
| - | - |
| `data-grid` | `"coarse"` for thirds, `"fine"` or `"none"` |
| `data-visible` | While a grid shows |
| `data-axis` | `"x"` on vertical lines, `"y"` on horizontal ones |
| `data-coarse` | On each line of the thirds grid |

| Variable | What it sets |
| - | - |
| `--zriz-grid` | Paints the grid lines. [Styling](https://zriz.dev/docs/styling.md) lists its default |
