Skip to main content
Gremorie

Panel

Floating corner overlay inside a Canvas. Pre-themed bordered card surface for canvas-level controls, status indicators, or contextual widgets.

Overview

Panel is a Gremorie skin over xyflow's Panel primitive. It anchors to a corner of the Canvas viewport and stays put as the canvas pans and zooms - which makes it the right surface for canvas-level controls (save, export, layout actions), status indicators (agent thinking, deployment state), or contextual widgets that should always be reachable.

The Gremorie chrome adds a m-4 margin, a rounded border, a bg-card surface and p-1 padding so the panel reads as a self-contained tile rather than floating raw content over the workflow.

For per-node action bars, use Toolbar. For zoom and fit controls, use Controls. Panel covers the rest.

Preview

'use client';import '@xyflow/react/dist/style.css';import { Canvas, Panel } from '@gremorie/rx-ai';import { Button } from '@gremorie/rx-forms';import {  type Edge as FlowEdge,  type Node as FlowNode,  ReactFlowProvider,} from '@xyflow/react';import { PlusIcon, SparklesIcon } from 'lucide-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 PanelPreview() {  return (    <div className="h-[360px] w-full">      <ReactFlowProvider>        <Canvas edges={gridEdges} nodes={gridNodes}>          <Panel position="top-right">            <div className="flex items-center gap-1">              <Button size="sm" variant="ghost">                <PlusIcon className="size-4" />                Add node              </Button>              <Button size="sm" variant="ghost">                <SparklesIcon className="size-4" />                Auto-layout              </Button>            </div>          </Panel>        </Canvas>      </ReactFlowProvider>    </div>  );}

Anatomy

Panel   docked overlay container — leaf (rendered inside Canvas)

Installation

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

Requires @xyflow/react.

Usage

import { Canvas, Panel } from "@gremorie/rx-ai";
import { Button } from "@gremorie/rx-forms";

export function Workflow() {
  return (
    <Canvas nodes={nodes} edges={edges}>
      <Panel position="top-right">
        <Button size="sm" onClick={save}>Save</Button>
      </Panel>
    </Canvas>
  );
}

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

API

<Panel>

Forwards all PanelProps from @xyflow/react. The Gremorie wrapper only adds chrome.

PropTypeDefaultDescription
position"top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right""top-left"Corner the panel docks to. xyflow default.
childrenReactNode-Panel content. Buttons, status pills, mini-forms, etc.
classNamestring-Extra classes. Merged with the default chrome via cn.

Default chrome: m-4 overflow-hidden rounded-md border bg-card p-1.

Composition

  1. <Canvas> is the parent. Multiple Panels can coexist - one per corner / side.
  2. Content is free-form. Drop buttons, dropdowns, status pills, mini-forms, or anything else.
  3. For dense panels, consider increasing the padding via className="p-3". The default p-1 is tuned for single icon-button rows.

Variations

Save / publish actions

A short row of buttons in the top-right that survives any canvas pan and zoom.

<Panel position="top-right" className="flex gap-2 p-2">
  <Button size="sm" variant="outline" onClick={discard}>
    Discard
  </Button>
  <Button size="sm" onClick={save}>
    Save
  </Button>
</Panel>

Status indicator

Top-left status pill that mirrors agent execution state.

<Panel position="top-left" className="px-3 py-2">
  <div className="flex items-center gap-2 text-xs font-medium">
    <span className="size-2 animate-pulse rounded-full bg-emerald-500" />
    Agent running
  </div>
</Panel>

Bottom-center insertion bar

For a "drop a new node here" affordance, put a single button in the bottom-center.

<Panel position="bottom-center" className="px-3 py-2">
  <Button size="sm" onClick={addStep}>
    <PlusIcon className="size-4" />
    Add step
  </Button>
</Panel>

Compose with form primitives for inline search or quick-edit affordances.

<Panel position="top-left" className="p-2">
  <Input className="w-48" placeholder="Search nodes..." />
</Panel>

Accessibility

  • Keyboard: Panel content is regular React. Tab order follows the DOM. Children should carry their own labels (aria-label, aria-describedby) as needed.
  • Focus visible: The Panel surface does not capture focus by itself. Its children do.
  • Screen readers: A Panel pinned to the corner does not have a built-in region role. If the panel hosts a critical workflow status, wrap it in a <section aria-label="..."> (or pass role="region" + aria-label directly).
  • Reduced motion: There is no animation on the surface. Custom transitions you add via className should respect prefers-reduced-motion.
  • Canvas - the surface that hosts panels
  • Controls - canvas-anchored zoom and fit controls
  • Toolbar - per-node selection-anchored action bar

On this page