Ready-made UI Components
The React package ships a set of styled, themeable UI components so you don't have to build a toolbar and style panel from scratch. They live under the @linkurious/ogma-annotations-react/ui subpath and are completely optional — importing the main package entry stays headless and pulls in none of this code or CSS.
Prefer to build your own? See Building a Toolbar, Building a Style Panel and Annotation List. The ready-made components are built on the same
useAnnotationsContexthook, so you can mix and match.
Installation
The components are part of the package — no extra install. Import them from the /ui subpath and load the stylesheet once in your app:
import {
AnnotationPanelController,
AddMenu,
ViewControls
} from "@linkurious/ogma-annotations-react/ui";
// Load once, e.g. in your entry file:
import "@linkurious/ogma-annotations-react/ui/styles.css";Why a separate subpath?
Keeping the UI on /ui means consumers who only want the headless editor pay nothing for the styled components or their CSS. The icons are inline SVG, so there is no icon font or extra icon dependency to wire up.
Putting it together
Drop the components inside an AnnotationsContextProvider (see the provider docs):
import { Ogma } from "@linkurious/ogma-react";
import { AnnotationsContextProvider } from "@linkurious/ogma-annotations-react";
import {
AnnotationPanelController,
AddMenu,
ViewControls
} from "@linkurious/ogma-annotations-react/ui";
import "@linkurious/ogma-annotations-react/ui/styles.css";
export function Editor({ graph }) {
return (
<Ogma graph={graph}>
<AnnotationsContextProvider>
{/* Toolbar: add arrow/comment/sticky note/box/text/polygon, undo/redo, erase/delete */}
<AddMenu />
{/* Center / rotate the view */}
<ViewControls />
{/* Style panel that follows the current selection */}
<AnnotationPanelController />
</AnnotationsContextProvider>
</Ogma>
);
}That's a full editor: a drawing toolbar, view controls, and a style panel that appears when you select an annotation and lets you edit color, background, font, line type, stroke width, and arrow extremities.

Components
AnnotationPanelController
A turnkey style panel. It listens to the editor's selection and shows the AnnotationPanel for the selected annotation, hiding it during drags and when nothing is selected.
| Prop | Type | Description |
|---|---|---|
placement | PanelPlacement (optional) | Which screen edge/corner the panel docks to. Defaults to "right". |
orientation | PanelOrientation (optional) | "vertical" (default) or "horizontal". |
<AnnotationPanelController placement="top-right" orientation="horizontal" />

If you want to control rendering yourself, use the useAnnotationPanel hook, which returns the current annotation and visible state:
import { useAnnotationPanel, AnnotationPanel } from "@linkurious/ogma-annotations-react/ui";
function MyPanel() {
const { annotation, visible } = useAnnotationPanel();
return <AnnotationPanel visible={visible} annotation={annotation} />;
}AnnotationPanel
The presentational style panel. Renders the right set of controls for the given annotation type (arrow, text/box/comment, or polygon). You normally render it via AnnotationPanelController, but you can drive it directly.
| Prop | Type | Description |
|---|---|---|
annotation | Annotation | null | The annotation to edit. |
visible | boolean | Whether the panel is shown. |
placement | PanelPlacement (optional) | Which screen edge/corner the panel docks to. Defaults to "right". |
orientation | PanelOrientation (optional) | "vertical" (default) or "horizontal". |
PanelPlacement is one of "left", "right" (default), "top", "bottom", "top-left", "top-right", "bottom-left", "bottom-right" — applied as a data-placement attribute and handled entirely in CSS, same as the vanilla AnnotationPanel it wraps. AddMenu doesn't yet support the same docking system (its position is left to your own CSS); the vanilla-only AnnotationToolbar does.
AddMenu
The drawing toolbar: buttons for arrow, comment, sticky note, box, text and polygon, plus undo / redo and erase. Optional export buttons appear only when you pass the corresponding callback. A sticky note is a plain, resizable text annotation (Miro-style: padded, colored, no connector), placed the same way as a box - click for a default square size, or drag to size it. Erase toggles a mode where clicking any annotation deletes it immediately, and is shown by default; the select-then-trash Delete button overlaps with it and is opt-in via deleteMode.

| Prop | Type | Description |
|---|---|---|
enabledTypes | ToolbarDrawingType[] (optional) | Which drawing tools to show, and in what order. Defaults to all six: ["arrow", "comment", "sticky-note", "box", "text", "polygon"]. |
styles | AnnotationToolbarStyles (optional) | Per-type default style overrides for the drawing tool buttons. |
deleteMode | "select" | "erase" | "both" (optional) | Which deletion control(s) to show. Defaults to "erase". |
onJsonExport | () => void (optional) | Show a JSON export button that calls this. |
onSvgExport | () => void (optional) | Show an SVG export button that calls this. |
<AddMenu onJsonExport={exportJson} onSvgExport={exportSvg} />Restrict the tools shown and override their default styles - only the properties you set change, everything else keeps its built-in default:
<AddMenu
enabledTypes={["arrow", "text"]}
styles={{
arrow: { strokeColor: "#0aa", strokeWidth: 3 },
text: { font: "Georgia", fontSize: 18 }
}}
/>ToolbarDrawingType and AnnotationToolbarStyles come from @linkurious/ogma-annotations/ui — the same types the vanilla AnnotationToolbar uses.
ViewControls
Center-view and rotate-view buttons. Uses the Ogma instance from context; no props.
Field controllers
The panel is composed from small controllers you can reuse to build a custom panel: ColorController, BackgroundController, FontController, ExtremityController, SliderController, LineTypeController. Each takes the target annotation and renders one section.
Icon
The inline-SVG icon used throughout the components, in case you want to match the look in your own UI.
| Prop | Type | Description |
|---|---|---|
name | IconName | One of the shared icon names. |
size | number (optional, default 18) | Width/height in px. |
rotate | boolean (optional) | Rotate 180°. |
className | string (optional) | Extra class. |
Theming
The stylesheet is driven by CSS custom properties. Override them on the panel (or any ancestor) to restyle without forking the CSS — the defaults preserve the out-of-the-box look:
.annotation-panel {
--oa-accent: #0aa; /* active state, selected option, slider thumb, etc. */
--oa-panel-bg: #fff;
--oa-panel-radius: 10px;
--oa-control-bg: #eee;
--oa-text-color: #333;
--oa-muted-color: #666;
}The accent also falls back to a legacy --brand variable if you already set one in your app.