component

Pan Zoom

props · 57 shown · 57 total

Content

  • children slot svelte
    Snippet

    Content to pan and zoom — any DOM, image, or SVG.

Appearance

  • "cyan" "danger" "dynamic" "mauve" "neutral" "pink" "primary" "sage" "slate" "stone" "success" "teal" "violet" "warning"

    The color family the highlight active state paints in (`activeEmphasis="highlight"`), independent of `tone` — e.g. a primary current row in a neutral list. Ignored at other levels.

  • "transparent" "surface.peak" "surface.hill" "surface.base" "surface.valley" "surface.ground"
    default surface.peak

    Surface background from the Panel scale (`surface.peak` → `surface.ground`, or `transparent`).

  • "none" "default" "bold" "muted" "accent"
    default default

    Border color at rest: `none`, `default`, `bold`, `muted`, or `accent`. The 1px line is always reserved when a border can appear, so changing it never shifts layout.

  • "inherit" "none" "default" "bold" "muted" "accent"

    Border color while the surface is `active` — the explicit form of the ring `activeEmphasis` would otherwise pick. It holds through hover, so a `borderInteract` color can't steal it. `inherit` keeps whatever `activeEmphasis` chose; `none` clears it.

  • "none" "default" "bold" "muted" "accent"

    Border color on hover and press: `none`, `default`, `bold`, `muted`, or `accent`. Composes with `border`, e.g. a muted line at rest that turns bold on hover.

  • false CardFrameProps<TSlot>

    Frame the canvas in a Card: a header from the card props (`heading`, `subheading`, `eyebrow`, `leading`, `trailing` for toolbar actions), an optional `footer`, and the canvas as the card content — edge to edge, filling the card's height. The zoom/fit/fullscreen controls, indicator and minimap stay overlaid on the canvas, and fullscreen takes the whole card. The pan-zoom surface props (`background`, `border`, `radius`, …) become the card's defaults. A rendered heading labels the viewport (`aria-labelledby`) unless `label` is set. Unset (or `false`) renders the bare canvas — the pre-card DOM.

  • "primary" "secondary" "tertiary"
    default secondary

    Which surface ramp the panel paints with: `primary` is the filled tone accent (with contrast text), `secondary` the tone's own surface tint, `tertiary` the neutral ramp with tone-accent text. `background` then picks the step on that ramp.

  • "highlight" "surface"

    What hover and press paint on an interactive surface: `surface` steps the resting surface ramp; `highlight` paints the tone's highlight (`neutral.highlight` on a neutral surface) and its next step while pressed. An active surface keeps its own hover steps.

  • "lg" "md" "sm" "xl" "xs" "none"
    default none

    Elevation shadow applied to the surface.

  • size deprecated
    unknown

    Ignored. Accepted for one release so existing call sites keep type-checking; it never changed the rendered height. Size the component with CSS (a `height` on it or its parent) or the `--pan-zoom-viewport-min-height` variable (`220px` floor by default).

  • "inherit" "cyan" "danger" "dynamic" "mauve" "neutral" "pink" "primary" "sage" "slate" "stone" "success" "teal" "violet" "warning"
    default "neutral"

    Semantic tone color forwarded via `colorPalette`. Tints the container surface, focus ring, minimap rectangle, and accent surfaces.

  • boolean

    Frosted glass: the chosen `background` step at /35 with a large backdrop blur, so content behind the panel shows through. A transparent background stays transparent.

Layout

  • "contain" "cover" "actual-size"
    default "contain"

    How `reset()` and the reset button lay content out: fit-with-padding (`contain`), fill the viewport (`cover`), or 1:1 (`actual-size`).

  • number
    default 16

    Padding (px) kept around the content when fitting it to the viewport. This is the FIT inset, not a CSS box padding — the Panel surface underneath is always `padding: "none"` so the viewport fills the container.

  • "inherit" "2xl" "lg" "md" "sm" "xl" "inner" "xs" "none" "2xs" "3xl" "4xl" "5xl" "6xl" "full"
    default md

    Corner radius from the radii scale (`full` for fully rounded). `inner` computes a concentric corner from the parent panel's radius minus its padding; `inherit` mirrors the parent's corner exactly, for a child that sits flush with its edge.

  • "inherit" "2xl" "lg" "md" "sm" "xl" "inner" "xs" "none" "2xs" "3xl" "4xl" "5xl" "6xl" "full"

    Corner radius for the bottom-left and bottom-right corners.

  • "inherit" "2xl" "lg" "md" "sm" "xl" "inner" "xs" "none" "2xs" "3xl" "4xl" "5xl" "6xl" "full"

    Corner radius for the top-left and bottom-left corners.

  • "inherit" "2xl" "lg" "md" "sm" "xl" "inner" "xs" "none" "2xs" "3xl" "4xl" "5xl" "6xl" "full"

    Corner radius for the top-right and bottom-right corners.

  • "inherit" "2xl" "lg" "md" "sm" "xl" "inner" "xs" "none" "2xs" "3xl" "4xl" "5xl" "6xl" "full"

    Corner radius for the top-left and top-right corners.

  • boolean

    Keep (or drop) the always-1px transparent border the panel reserves so a border appearing or changing never shifts layout. Computed automatically — it's reserved when a resting `border` is visible, or when `interactive` / `borderInteract` / `active` can change the border at runtime. Set `false` only on a panel that must not occupy that 1px (e.g. a borderless housing frame that would otherwise add 2px around a set).

  • boolean
    default false

    Opt this panel into the baseline rhythm: bakes `data-rhythm` on the root, so the whole subtree becomes a rhythm scope. The panel's padding turns into whole raster lines (minus its border) and text inside can quantise its own leading through the preset's `rhythm` pattern. A `<Grid rhythm>` (or any `[data-rhythm]`) ancestor makes the subtree rhythmic without this prop — the prop is how a panel opts ITSELF in, and how it takes the line-based padding.

Behavior

  • boolean "current" "checked" "current-within"
    default false

    Mark this as the chosen one in a set (a current nav item, a checked option, a selected card). Where `interactive` says it *can* be clicked, `active` says it *is* the current choice. Use `activeEmphasis` to control how loud the state is. Combined with `interactive`, hover and press restart their stepping from the active baseline rather than falling back to the unchosen ramp. The four values differ only in what drives the state: `true` by the prop (via `data-panel-active`), `"checked"` by a wrapped native input (`:has(input:checked)` — zero JS, nothing to re-render), `"current"` by an existing `aria-current` on the panel, and `"current-within"` by an `aria-current` on a direct child (a split nav row whose link carries it).

  • "primary" "secondary" "tertiary" "highlight"
    default the panel's `emphasis`

    How loud the `active` state is. Defaults to the panel's own `emphasis`, so the chosen state lands on the same ramp as the resting look — this prop is the override for when the active item should be louder (or quieter) than the panel itself. `"primary"` fills with the tone accent ramp and flips text to the contrast scale (~150 RGB units of separation — the option that reads at a glance in a dense list). `"secondary"` tints the tone surface ramp and `"tertiary"` the neutral ramp; both promote text to `bold` and lift the border to the default line, but move the surface only ~7–18 units.

  • number
    default 150

    Duration of smooth-zoom transitions, in milliseconds.

  • "div" "section" "article" "aside" "main" "header" "footer" "nav" "dialog" "form" "fieldset" "ul" "ol" "li" "a" "button" "label" "span" "kbd"
    default "div"

    HTML element to render. Curated to container-like tags so semantic intent stays clear (no html/script/style/etc).

  • boolean
    default false

    Constrain panning so the content can be dragged exactly to each of its edges and no further: on an axis where the scaled content is larger than the viewport the translation is clamped to `[viewport − content × scale, 0]` (no empty band ever shows); on an axis where it is smaller, the content is held centered. Applies to every pan — drag, wheel, keys, `setTranslate`, `panBy`, and the controlled `translation` prop.

  • boolean
    default false

    Disable all interaction and dim the component.

  • boolean
    default true

    Enable double-tap-to-zoom on touch devices.

  • boolean

    Enable interactive (hover / focus / press) affordances and states.

  • number
    default 5

    Highest zoom level the user can reach.

  • number

    Lowest zoom level the user can reach. When omitted it is auto-computed to fit the content with padding (never below `0.01`).

  • (isFullscreen: boolean) => void

    Fires when fullscreen is entered or exited.

  • (translate: Point) => void

    Fires whenever the pan translation changes.

  • onZoomChange svelte
    (scale: number) => void

    Fires whenever the zoom level changes (gesture, button, key, or set).

  • 0 1 2
    default 0

    Which mouse button starts a drag-pan: `0` left, `1` middle, `2` right. Picking `2` also suppresses the viewport's context menu.

  • boolean
    default true

    Whether dragging the viewport pans the content. Turn it off when the content owns the drag gesture (a canvas whose empty space rubber-band selects, an editor with its own marquee). Individual descendants can opt out without disabling panning wholesale by carrying a `data-no-pan` attribute — a drag starting on that element, or anywhere inside it, is left alone.

  • number
    default 1

    Pinch-gesture sensitivity. Lower values make pinch-zoom more sensitive.

  • boolean
    default true

    Double-click (or double-tap) resets the view to the fitted state.

  • "preserve" "refit"
    default "preserve"

    What a viewport resize does to the view. `"preserve"` re-fits an untouched view but keeps a panned/zoomed framing (the content point at the viewport centre stays put, same zoom, re-clamped by `constrainToBounds`); `"refit"` re-fits on every resize, discarding pan/zoom.

  • boolean
    default true

    Render the zoom in/out/reset (and optionally fullscreen) control buttons.

  • boolean
    default true

    Render the fullscreen toggle button (within the controls).

  • boolean
    default false

    Render a minimap overview with a draggable viewport rectangle.

  • boolean
    default false

    Render the live zoom-percentage readout.

  • boolean
    default true

    Animate discrete zoom steps (buttons, keys, double-click). Drag and pinch are always instant. Ignored under `prefers-reduced-motion: reduce`.

  • Point

    Controlled pan translation (px, viewport space) — the content's top-left offset inside the viewport, i.e. the `translate()` of its transform. Applied once the first fit has landed and again whenever it changes; `constrainToBounds` still clamps it. Pair with `onTranslationChange` (React/Vue) or `bind:translation` (Svelte) to read and correct the framing. In Astro it is the initial translation only.

  • "ctrl-zoom" "zoom" "pan"
    default "ctrl-zoom"

    What a wheel / trackpad scroll does. `"ctrl-zoom"` zooms only with Ctrl/⌘ held (leaving plain scroll to the page), `"zoom"` always zooms, and `"pan"` scrolls the content on both axes while Ctrl-scroll still zooms.

  • number
    default 0.05

    Wheel / trackpad zoom sensitivity. Higher zooms faster per wheel tick.

  • number
    default 1

    Initial / controlled zoom level. Two-way bindable in Svelte (`bind:zoom`) and controllable in React (`zoom` + `onZoomChange`).

  • boolean
    default false

    Double-click (or double-tap) zooms in toward the pointer instead of resetting. Takes precedence over `resetOnDoubleClick`.

  • number
    default 0.2

    Zoom step applied by the zoom-in/zoom-out buttons, `+`/`-` keys, and double-click-to-zoom.

Accessibility

  • string
    default "Pan and zoom viewport"

    Accessible label for the interactive viewport region.

Advanced

  • controller svelte
    HeadlessPanZoom

    Bindable, read-only reference to the headless controller (`bind:controller`) — the same instance `onReady` gets. Available from mount; sizes are only real once `onReady` has fired.

  • element binding svelte
    HTMLElement null

    Bindable reference to the canvas container element (the element the controller binds — inside the card content when `card` is set). Typed `HTMLElement` because the container is a Panel root — `as` can render any container tag.

  • onReady svelte
    (controller: HeadlessPanZoom) => void

    Fires once, right after the first fit with real viewport dimensions, with the headless controller — read the framing (`$scale`, `$translate`), subscribe to it, or drive it (`setTranslate`, `panBy`, `fitToBounds`, `setZoom`, …).

  • PanZoomPassThrough< ContainerEl, ViewportEl, ContentEl, ControlsEl, ZoomInButtonEl, ZoomOutButtonEl, ResetButtonEl, FullscreenButtonEl, ZoomIndicatorEl, MinimapEl >

    Per-slot style and HTML-attribute override bag.

  • boolean
    default false

    Astro / vanilla: serialize the props into `data-pan-zoom-config` so the client runtime hydrates this instance and `getPindoba(el, "pan-zoom")` can `update()` it (the Astro component sets it itself). Frameworks with their own reactivity don't need it.

Plus all standard <div> HTML attributes.

Type

  • Components
  • Blocks