Skip to main content
Gremorie

Controls

Themed corner controls for a Canvas. Zoom in, zoom out, fit view and lock interaction, all skinned with Gremorie tokens.

Overview

Controls is a Gremorie skin over Controls from @xyflow/react. It docks to the bottom-left of a Canvas by default and exposes the standard interaction buttons: zoom in, zoom out, fit view, and a lock toggle that disables panning and node interaction.

The Gremorie chrome strips xyflow's heavy borders and shadows in favor of a single rounded border, a bg-card background and ghost-style buttons that pick up bg-secondary on hover. This keeps the controls visually quiet so they do not compete with the workflow content.

Use whenever a canvas needs zoom controls (any read-write graph editor) or read-only navigation aids (agent traces, large flow visualizations).

Preview

'use client';import '@xyflow/react/dist/style.css';import { Canvas, Controls } from '@gremorie/rx-ai';import {  type Edge as FlowEdge,  type Node as FlowNode,  ReactFlowProvider,} from '@xyflow/react';const gridNodes: FlowNode[] = [  { id: '1', position: { x: 0, y: 0 }, data: { label: 'A' } },  { id: '2', position: { x: 200, y: 80 }, data: { label: 'B' } },];const gridEdges: FlowEdge[] = [{ id: 'e1-2', source: '1', target: '2' }];export function ControlsPreview() {  return (    <div className="h-[360px] w-full">      <ReactFlowProvider>        <Canvas edges={gridEdges} nodes={gridNodes}>          <Controls />        </Canvas>      </ReactFlowProvider>    </div>  );}

Anatomy

Controls   zoom · fit-view · interactivity cluster — leaf (inside Canvas)

Installation

bash npx gremorie@latest add rx-controls
bash pnpm dlx gremorie@latest add rx-controls
bash yarn dlx gremorie@latest add rx-controls
bash bunx --bun gremorie@latest add rx-controls

Requires @xyflow/react.

Usage

import { Canvas, Controls } from "@gremorie/rx-ai";

export function Workflow() {
  return (
    <Canvas nodes={nodes} edges={edges}>
      <Controls />
    </Canvas>
  );
}

The Angular edition of this component is planned; the React edition is production-ready today.

API

<Controls>

Forwards all ControlProps from @xyflow/react. The Gremorie wrapper only restyles - it never overrides behavior props.

PropTypeDefaultDescription
position"top-left" | "top-right" | "bottom-left" | "bottom-right""bottom-left"Corner the controls dock to. xyflow default.
showZoombooleantrueShow the zoom in / out buttons.
showFitViewbooleantrueShow the fit-view button.
showInteractivebooleantrueShow the lock toggle. Set to false for read-only canvases.
fitViewOptionsFitViewOptions-Forwarded to the fit-view action (padding, duration, etc.).
onZoomIn / onZoomOut / onFitView / onInteractiveChangecallbacks-Hooks into each control.
childrenReactNode-Extra control buttons appended to the strip. Each child should follow xyflow's ControlButton API.
classNamestring-Extra classes.

Default chrome added by Gremorie: gap-px overflow-hidden rounded-md border bg-card p-1 shadow-none!. Child buttons are restyled to rounded-md, transparent background, hover state bg-secondary.

Composition

  1. <Canvas> is the parent. Controls must be rendered as a child so xyflow's internal Panel machinery can position it relative to the viewport.
  2. Built-in buttons (zoom in, zoom out, fit view, lock) render automatically based on the showZoom / showFitView / showInteractive props.
  3. Custom buttons can be appended via children. Use ControlButton from @xyflow/react to keep the styling consistent.

Variations

Default

Bottom-left, all four buttons.

<Canvas nodes={nodes} edges={edges}>
  <Controls />
</Canvas>

Read-only canvas

Hide the lock toggle when the canvas is non-interactive anyway.

<Canvas nodes={nodes} edges={edges} nodesDraggable={false}>
  <Controls showInteractive={false} />
</Canvas>

Custom control button

Append a "reset" or "auto-layout" button using xyflow's ControlButton.

import { ControlButton } from '@xyflow/react';
import { LayoutGridIcon } from 'lucide-react';

<Canvas nodes={nodes} edges={edges}>
  <Controls>
    <ControlButton onClick={autoLayout} title="Auto-layout">
      <LayoutGridIcon className="size-4" />
    </ControlButton>
  </Controls>
</Canvas>;

Docked top-right

For canvases where the bottom-left is reserved for something else (status bar, agent thinking widget), move the controls.

<Canvas nodes={nodes} edges={edges}>
  <Controls position="top-right" />
</Canvas>

Accessibility

  • Keyboard: Each built-in control is a real button. Tab focuses each one in order; Enter or Space activates.
  • Labels: xyflow ships title attributes on the built-in buttons ("zoom in", "zoom out", "fit view", "toggle interactivity"). For custom buttons, supply title (and ideally aria-label) so the icon-only chrome is announced.
  • Focus visible: The Gremorie hover style (bg-secondary) does not interfere with xyflow's default focus ring. Do not strip outline.
  • Reduced motion: Zoom and pan animations are governed by xyflow and honor prefers-reduced-motion.
  • Canvas - the surface that hosts Controls
  • Panel - free-floating overlay if you need a more flexible corner widget
  • Toolbar - per-node floating actions (different concern - selection-anchored, not canvas-anchored)

On this page