Panel
Canvas overlay panel positioned in a corner of the workflow.
Legend
active flow
conditional
Legend
active flow
conditional
import { Canvas } from "@/components/ai/canvas";import { Panel } from "@/components/ai/panel";import { Button } from "@/components/ui/button";
export default function Demo() { return ( <div className="h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <Canvas edges={[]} nodes={[]}> <Panel className="px-3 py-2.5 text-xs" position="top-left"> <p className="mb-1.5 font-semibold">Legend</p> <p className="flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"> <path d="M0 3h26" stroke="var(--brand)" strokeDasharray="6 5" strokeWidth="1.6" /> </svg> active flow </p> <p className="mt-1 flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"> <path d="M0 3h26" stroke="var(--muted-foreground-2)" strokeDasharray="2 5" strokeWidth="1.6" /> </svg> conditional </p> </Panel> <Panel className="flex items-center gap-1.5" position="top-right"> <Button size="sm">Run</Button> <Button size="sm" variant="outline"> Save </Button> </Panel> </Canvas> </div> );}<script setup lang="ts">import { Canvas } from "@/components/ai/canvas";import { Panel } from "@/components/ai/panel";import { Button } from "@/components/ui/button";</script>
<template> <div class="h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <Canvas :nodes="[]" :edges="[]"> <Panel position="top-left" class="px-3 py-2.5 text-xs"> <p class="mb-1.5 font-semibold">Legend</p> <p class="flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--brand)" stroke-dasharray="6 5" stroke-width="1.6" /></svg> active flow </p> <p class="mt-1 flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--muted-foreground-2)" stroke-dasharray="2 5" stroke-width="1.6" /></svg> conditional </p> </Panel> <Panel position="top-right" class="flex items-center gap-1.5"> <Button size="sm">Run</Button> <Button size="sm" variant="outline">Save</Button> </Panel> </Canvas> </div></template><script lang="ts"> import { Canvas } from "$lib/components/ai/canvas"; import { Panel } from "$lib/components/ai/panel"; import { Button } from "$lib/components/ui/button";</script>
<div style="height: 224px" class="w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <Canvas nodes={[]} edges={[]}> <Panel position="top-left" class="px-3 py-2.5 text-xs"> <p class="mb-1.5 font-semibold">Legend</p> <p class="flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--brand)" stroke-dasharray="6 5" stroke-width="1.6" /></svg> active flow </p> <p class="mt-1 flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--muted-foreground-2)" stroke-dasharray="2 5" stroke-width="1.6" /></svg> conditional </p> </Panel> <Panel position="top-right" class="flex items-center gap-1.5"> <Button size="sm">Run</Button> <Button size="sm" variant="outline">Save</Button> </Panel> </Canvas></div>Workflow only: it is not the ui inset-panel.
Installation
Section titled “Installation”npx shadcn@latest add @edmi-ui/ai-panelpnpm dlx shadcn@latest add @edmi-ui/ai-panelyarn dlx shadcn@latest add @edmi-ui/ai-panelbunx shadcn@latest add @edmi-ui/ai-panelPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @xyflow/reactTerminal window pnpm add @xyflow/reactTerminal window yarn add @xyflow/reactTerminal window bun add @xyflow/reactCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-vue@latest add @edmi-ui/ai-panelpnpm dlx shadcn-vue@latest add @edmi-ui/ai-panelyarn dlx shadcn-vue@latest add @edmi-ui/ai-panelbunx shadcn-vue@latest add @edmi-ui/ai-panelPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Install the dependencies:
Terminal window npm install @vue-flow/core @vueuse/coreTerminal window pnpm add @vue-flow/core @vueuse/coreTerminal window yarn add @vue-flow/core @vueuse/coreTerminal window bun add @vue-flow/core @vueuse/coreCopy the code from Component source into your project and update the import paths to match your aliases.
npx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-panel.jsonpnpm dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-panel.jsonyarn dlx shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-panel.jsonbunx --bun shadcn-svelte@latest add https://viandwi24.github.io/edmi-ui/r/svelte/ai-panel.jsonPick your package manager above; the choice is remembered. Add the @edmi-ui registry first, see Getting started.
Copy the code from Component source into your project and update the import paths to match your aliases.
import { Canvas } from "@/components/ai/canvas";import { Panel } from "@/components/ai/panel";import { Button } from "@/components/ui/button";
<div className="h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <Canvas edges={[]} nodes={[]}> <Panel className="px-3 py-2.5 text-xs" position="top-left"> <p className="mb-1.5 font-semibold">Legend</p> <p className="flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"> <path d="M0 3h26" stroke="var(--brand)" strokeDasharray="6 5" strokeWidth="1.6" /> </svg> active flow </p> {/* … */} </Panel> <Panel className="flex items-center gap-1.5" position="top-right"> <Button size="sm">Run</Button> <Button size="sm" variant="outline"> Save </Button> </Panel> </Canvas></div><script setup lang="ts">import { Canvas } from "@/components/ai/canvas";import { Panel } from "@/components/ai/panel";import { Button } from "@/components/ui/button";</script>
<template> <div class="h-56 w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <Canvas :nodes="[]" :edges="[]"> <Panel position="top-left" class="px-3 py-2.5 text-xs"> <p class="mb-1.5 font-semibold">Legend</p> <p class="flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--brand)" stroke-dasharray="6 5" stroke-width="1.6" /></svg> active flow </p> <p class="mt-1 flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--muted-foreground-2)" stroke-dasharray="2 5" stroke-width="1.6" /></svg> conditional </p> </Panel> <Panel position="top-right" class="flex items-center gap-1.5"> <Button size="sm">Run</Button> <Button size="sm" variant="outline">Save</Button> </Panel> </Canvas> </div></template><script lang="ts"> import { Canvas } from "$lib/components/ai/canvas"; import { Panel } from "$lib/components/ai/panel"; import { Button } from "$lib/components/ui/button";</script>
<div style="height: 224px" class="w-full overflow-hidden rounded-[calc(var(--radius)*1.4)] border border-border"> <Canvas nodes={[]} edges={[]}> <Panel position="top-left" class="px-3 py-2.5 text-xs"> <p class="mb-1.5 font-semibold">Legend</p> <p class="flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--brand)" stroke-dasharray="6 5" stroke-width="1.6" /></svg> active flow </p> <p class="mt-1 flex items-center gap-2"> <svg aria-hidden="true" height="6" width="26"><path d="M0 3h26" stroke="var(--muted-foreground-2)" stroke-dasharray="2 5" stroke-width="1.6" /></svg> conditional </p> </Panel> <Panel position="top-right" class="flex items-center gap-1.5"> <Button size="sm">Run</Button> <Button size="sm" variant="outline">Save</Button> </Panel> </Canvas></div>Component source
Section titled “Component source”import { Panel as PanelPrimitive } from "@xyflow/react";import { cn } from "cn";import type { ComponentProps } from "react";
export type PanelProps = ComponentProps<typeof PanelPrimitive>;
/** Any UI pinned to a canvas corner (legend, filters, run buttons). Workflow only, not the ui inset panel. */export const Panel = ({ className, ...props }: PanelProps) => ( <PanelPrimitive data-slot="ai-panel" className={cn( "m-4 overflow-hidden rounded-[calc(var(--radius)*1.2)] border border-border bg-card p-1", className, )} {...props} />);<script setup lang="ts">import type { PanelPositionType } from "@vue-flow/core"import type { HTMLAttributes } from "vue"import { Panel as PanelPrimitive } from "@vue-flow/core"import { reactiveOmit } from "@vueuse/core"import { cn } from "@/registry/edmi/lib/utils"
/** Any UI pinned to a canvas corner (legend, filters, run buttons). Workflow only, not the ui inset panel. */const props = withDefaults(defineProps<{ class?: HTMLAttributes["class"] position?: PanelPositionType}>(), { position: "top-right",})
const delegatedProps = reactiveOmit(props, "class")</script>
<template> <PanelPrimitive data-slot="ai-panel" v-bind="delegatedProps" :class="cn('m-4 overflow-hidden rounded-[calc(var(--radius)*1.2)] border border-border bg-card p-1', props.class)" > <slot /> </PanelPrimitive></template>export { default as Panel } from "./Panel.vue";<script lang="ts"> import { Panel as PanelPrimitive, type PanelProps } from "@xyflow/svelte"; import { cn } from "$lib/utils.js";
/** Any UI pinned to a canvas corner (legend, filters, run buttons). Workflow only, not the ui inset panel. */ let { class: className, children, ...restProps }: PanelProps = $props();</script>
<PanelPrimitive data-slot="ai-panel" class={cn( "m-4 overflow-hidden rounded-[calc(var(--radius)*1.2)] border border-border bg-card p-1", className )} {...restProps}> {@render children?.()}</PanelPrimitive>import Panel from "./panel.svelte";
export { Panel };| Part | Prop | Type | Default |
|---|---|---|---|
| Panel | position |
top-left | top-center | top-right | bottom-left | bottom-center | bottom-right |