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.
| Prop | Type | Default | Description |
|---|---|---|---|
position | "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | "top-left" | Corner the panel docks to. xyflow default. |
children | ReactNode | - | Panel content. Buttons, status pills, mini-forms, etc. |
className | string | - | Extra classes. Merged with the default chrome via cn. |
Default chrome: m-4 overflow-hidden rounded-md border bg-card p-1.
Composition
<Canvas>is the parent. MultiplePanels can coexist - one per corner / side.- Content is free-form. Drop buttons, dropdowns, status pills, mini-forms, or anything else.
- For dense panels, consider increasing the padding via
className="p-3". The defaultp-1is 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>Mini-form / search
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 passrole="region"+aria-labeldirectly). - Reduced motion: There is no animation on the surface. Custom transitions you add via
classNameshould respectprefers-reduced-motion.