Build a stencil with context
Call getCropperContext() during component initialization. Its stable cropper API is available immediately. Register a getter for stencil options before state-dependent markup; the cropper reads it before the first reset and tracks subsequent reactive changes.
<script lang="ts">
import { MoveDiagonal } from '@lucide/svelte';
import {
DraggableArea,
getCropperContext,
StencilOverlay,
StencilWrapper,
type MoveDirections
} from 'svelte-advanced-cropper';
import { BoundingBoxType } from 'advanced-cropper/extensions/fit-to-image';
const context = getCropperContext();
const cropper = context.cropper;
context.registerStencil(() => ({ aspectRatio: 1, boundingBox: BoundingBoxType.Circle }));
const disabled = $derived(context.disabled);
const state = $derived(cropper.getState());
const coordinates = $derived(cropper.getStencilCoordinates());
const transitions = $derived(cropper.getTransitions());
function resize(shift: MoveDirections) {
// Only the horizontal shift is used, on both axes: the square stencil grows evenly.
cropper.resizeCoordinates('center', {
left: shift.left,
top: shift.left
});
}
</script>
{#if state}
<StencilWrapper class="circle-stencil" {transitions} {...coordinates}>
<DraggableArea
{disabled}
class="circle-stencil__handler"
onMove={resize}
onMoveEnd={cropper.resizeCoordinatesEnd}
>
<MoveDiagonal color="white" size={22} />
</DraggableArea>
<DraggableArea
{disabled}
class="circle-stencil__draggable-area"
onMove={(directions) => cropper.moveCoordinates(directions)}
onMoveEnd={cropper.moveCoordinatesEnd}
>
<StencilOverlay class="circle-stencil__overlay" />
</DraggableArea>
</StencilWrapper>
{/if}
<style>
:global(.circle-stencil) {
cursor: move;
}
:global(.circle-stencil__handler) {
position: absolute;
right: 15%;
top: 14%;
z-index: 1;
cursor: ne-resize;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
transform: translate(50%, -50%);
}
:global(.circle-stencil__overlay) {
border: dashed 2px white;
box-sizing: border-box;
border-radius: 50%;
}
:global(.circle-stencil__draggable-area) {
width: 100%;
height: 100%;
}
</style>- RectangleStencil / CircleStencil
child of Cropper or FixedCropper- getCropperContext()
registerStencil · reactive cropper, disabled, image -
-
- line
SimpleLine by default- LineWrapper → DraggableArea
- handler
SimpleHandler by default- HandlerWrapper → DraggableArea
-
-
- StencilGrid
grid prop - preview <div>
__preview selector
- children
custom guides inside the crop region
-
-
- Overlay
__overlayselector- Preview
__previewselector- Line
linesnippet,linesprop- Handler
handlersnippet,handlersprop- Stencil root
class,style;--moving,--resizing,--disabledstate selectors- Guides
gridprop or achildrensnippet
Set props directly on the child stencil. Scope part selectors under its class: append the
suffixes above to .advanced-cropper-rectangle-stencil or .advanced-cropper-circle-stencil.
Read reactive values
Use $derived(context.disabled), $derived(context.image) and $derived(context.cropper.getStencilCoordinates()). Reading a getter once into an ordinary constant takes a snapshot. image is the displayed image, including an image installed with setImage.
The effective disabled state is context.disabled || ownDisabled. A child cannot enable gestures disabled by its parent. Custom controls call the corresponding end method when their gesture finishes.
Constraint lifecycle
registerStencil(() => options) installs destruction cleanup itself and returns an idempotent cleanup for early removal. Options can include aspectRatio and boundingBox; a circle supplies both a square ratio and BoundingBoxType.Circle from the fit-to-image extension.
The cropper reconciles registration, removal, replacement and option changes even with autoReconcileState={false}. It does not reset the crop to defaults. More than one registration after an update settles is an error. Nested croppers isolate registrations; calling the getter outside a cropper throws.
Registration also works during SSR, without image loading, measurements or resets. Use the complete custom stencil tutorial for movement and resizing, and the context contract for exact types.