Skip to navigation

Crop area

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

Open
Download

Anatomy

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

<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 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:

[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:

[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:

WhenWhat shows
Press or move the cropThe 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 itThe fine grid fades in once the angle moves. A press that stays still shows none
Press a key on Area or ZoomNo new grid. A grid that already shows stays
Let go or stop moving the cropIt stays for a short hold, then fades out, see accessibility
Let go of the dialThe 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:

[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:

KeyWhat it does
arrow keysMove the crop by 1% of its size
shift+arrow keysMove it by 10%
alt+arrow keysResize 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×
0Jump 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. className and render get { shape, interacting }.

Prop
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
AttributeWhen
data-shape"rect" or "circle", from Root
data-visibleWhile a photo is placed
data-interactingDuring a gesture, and while a zriz key is held down
VariableWhat it sets
--zriz-framePaints the frame and the handle marks, #fff by default. Styling lists every colour
--zriz-rotationWith liveVariables, the straighten angle in degrees, like −4.5
--zriz-rotation-progressWith liveVariables, the angle over its limit, from −1 to 1
--zriz-zoomWith liveVariables, the zoom, 1 to maxZoom
--zriz-zoom-progressWith liveVariables, the zoom on a log scale, 0 to 1
--zriz-overscrollWith 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 }.

Prop
position HandleProps["position"] Required
The corner or edge it drags: "top-left", "top", "top-right", "right", "bottom-right", "bottom", "bottom-left", "left"
AttributeWhen
data-edgeAlways, set to its position
data-activeFrom a press on this handle until the pointer lets go, even if it never moves
VariableWhat it sets
--zriz-handle-sizeThe 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 }.

AttributeWhen
data-grid"coarse" for thirds, "fine" or "none"
data-visibleWhile a grid shows
data-axis"x" on vertical lines, "y" on horizontal ones
data-coarseOn each line of the thirds grid
VariableWhat it sets
--zriz-gridPaints the grid lines. Styling lists its default