> ## Documentation Index
> Fetch the complete documentation index at: https://docs.graphy.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom menus

Use `EditableGraphRenderer`'s `editMenus` prop to remove, replace or extend the controls for a geom, guide or chart background. Your entries take precedence over the built-in menus.

Set an entry to `null` to remove its rows:

```tsx theme={null}
import {
  EditableGraphRenderer,
  type EditMenus,
} from '@graphysdk/react/editable';

const editMenus: EditMenus = { grid: null, graph: null };

<EditableGraphRenderer mode="edit" editMenus={editMenus} />;
```

Axes, legends and grid lines keep their visibility button even without rows. In this example, clicking a grid line opens only the header and eye button; the chart background becomes unselectable. Likewise, `geoms: { bar: null }` makes bars unselectable.

Keep `editMenus` stable, either outside the component or with `useMemo`, to avoid re-registering menus on each render.

## Replace a menu

An edit menu receives `{ target }` and renders rows. Use `Row` for labels, `useControls()` for controls and `useGraphCommands()` to dispatch edits. This example keeps `ColorRow` and adds a button to round every bar in the selected layer:

```tsx theme={null}
import { useGraphCommands } from '@graphysdk/react';
import {
  ColorRow,
  Row,
  SetBarCornerRadiusCommand,
  useControls,
  type EditMenus,
  type ObservationsEditMenu,
} from '@graphysdk/react/editable';

const BarMenu: ObservationsEditMenu = ({ target }) => {
  const { dispatch } = useGraphCommands();
  const { Button } = useControls();

  return (
    <>
      <ColorRow target={target} />
      <Row label="Corners">
        <Button
          label="Round"
          onClick={() =>
            dispatch(
              new SetBarCornerRadiusCommand({
                layerId: target.layerId,
                cornerRadius: 'full',
              })
            )
          }
        />
      </Row>
    </>
  );
};

BarMenu.hasRows = ColorRow.hasRows;

const editMenus: EditMenus = { geoms: { bar: BarMenu } };
```

`target` is an `ObservationsTarget` with a `layerId`, `scope` (`observation`, `group` or `xValue`) and a predicate identifying the observations. `ColorRow` edits that selection; the corner-radius command above edits the whole layer. Both share the chart's undo history.

The optional static `hasRows(target, { scene, dataLabelPlacement, findGeom })` determines whether a target can be hovered or selected. Without it, the menu accepts every target. Reusing `ColorRow.hasRows` excludes selections whose color cannot be changed, such as stacked bands, matching the built-in bar menu.

To restrict a menu to groups:

```tsx theme={null}
BarMenu.hasRows = (target) => target.scope === 'group';
```

A component entry replaces the style menu used in edit mode. To also customize the menu for adding annotations in annotate mode, provide both actions:

```tsx theme={null}
const editMenus: EditMenus = {
  geoms: { bar: { style: BarMenu, annotate: null } },
};
```

You can compose the exported `BarEditMenu`, `LineEditMenu`, `PointEditMenu`, `AxisEditMenu`, `GridEditMenu`, `LegendEditMenu`, `ChartEditMenu`, `ColorRow` and `PaletteRow`. Reuse a menu's availability check when appropriate: `MyAxisMenu.hasRows = AxisEditMenu.hasRows`.

## Which menu a target gets

Lookup checks your entries first, then the built-in entries. A component supplies the rows; `null` stops lookup without rows; an omitted entry falls through to the defaults.

For observations, `layers` matches a geom, coordinate system and position adjustment. `geoms` matches a geom in any configuration. Within each set, `layers` takes precedence:

```tsx theme={null}
const editMenus: EditMenus = {
  layers: {
    bar: { cartesian: { stack: StackedBarMenu } },
  },
  geoms: {
    bar: BarMenu,
    candlestick: CandlestickMenu,
  },
};
```

Here, stacked cartesian bars use `StackedBarMenu`; all other bars use `BarMenu`. Coordinate keys are `cartesian`, `polar` and `flip`. Position keys are `identity`, `stack`, `dodge` and `fill`.

`geoms` also accepts custom geom names. Geoms with no registered menu fall back to `ColorRow`.

The built-in defaults are `PointEditMenu` for points, `LineEditMenu` for lines and areas, and `BarEditMenu` for bars. Rules and tiles have no menu. Guides and the chart use their corresponding exported menus.

## Swap the controls

Wrap the chart in `ControlRegistryProvider` to replace controls across its edit menus and [editor panels](https://docs.graphy.dev/sdk-next/editing/editor-panel.md):

```tsx theme={null}
import { GraphProvider } from '@graphysdk/react';
import {
  ControlRegistryProvider,
  EditableGraphRenderer,
  type SwitchControlProps,
} from '@graphysdk/react/editable';

const HostSwitch = (props: SwitchControlProps) => (
  <input
    type="checkbox"
    id={props.id}
    checked={props.checked}
    disabled={props.disabled}
    onChange={(event) => props.onChange(event.target.checked)}
  />
);

<ControlRegistryProvider controls={{ Switch: HostSwitch }}>
  <GraphProvider spec={spec} data={data}>
    <EditableGraphRenderer mode="edit" />
  </GraphProvider>
</ControlRegistryProvider>;
```

The registry contains `ToggleGroup`, `Switch`, `Slider`, `RadioGrid`, `Button`, `TextField`, `NumberField`, `Select`, `ColorSwatches`, `CustomColor` and `FileInput`. Omitted controls inherit from the surrounding provider or the defaults. Define replacement components outside render; the `controls` object can be inline.

Replacements use the exported props type, such as `SliderControlProps` or `SelectControlProps`. For live gestures, call `onChange` on each update and `onCommit` when the gesture ends. Omitting `onCommit` delays `onSpecChange` and can merge later gestures into the same undo step.

## Translate the menu

Menus use the chart's `formattingLocale`. Wrap the chart in `EditorIntlProvider` to choose another locale or override phrases:

```tsx theme={null}
import { GraphProvider } from '@graphysdk/react';
import {
  EditableGraphRenderer,
  EditorIntlProvider,
} from '@graphysdk/react/editable';

<EditorIntlProvider
  locale="pt-PT"
  i18nOverrides={{
    'editor.overlayMenu.chart': 'Gráfico',
    'editor.overlayMenu.fillColor': 'Cor',
    'editor.overlayMenu.allOf': ({ name }) => `Todos: ${name}`,
  }}
>
  <GraphProvider spec={spec} data={data}>
    <EditableGraphRenderer mode="edit" />
  </GraphProvider>
</EditorIntlProvider>;
```

Override phrases by dotted key, using a function for phrases with parameters. Built-in dictionaries cover `en-GB`, `en-US`, `pt-PT` and `ar` (right to left). Any BCP-47 tag is accepted: lookup tries the exact locale, then its language, then `en-GB`. Missing phrases also fall back to `en-GB`.

## Style the menu

The menu and editor panel share six CSS custom properties. Set them on `:root` to reach both. Menus render in a portal under `#graphy_root`, or `document.body` if that element is absent, so styles scoped to the chart's container may not reach them.

```css theme={null}
:root {
  --graphy-editor-accent: #0f62fe;
  --graphy-editor-surface: #ffffff;
  --graphy-editor-text: #161616;
  --graphy-editor-border: #e0e0e0;
  --graphy-editor-padding-x: 12px;
  --graphy-editor-padding-y: 10px;
}

[data-graphy-color-scheme='dark'] {
  --graphy-editor-surface: #262626;
  --graphy-editor-text: #f4f4f4;
}
```

`surface` and `text` determine field backgrounds, secondary text and focus outlines. `accent` colors active controls. `border` defaults to the text color at 12% opacity. The padding values apply to menus and panel sections. The portal wrapper carries `data-graphy-color-scheme` for light and dark overrides.

For menu-only overrides, use the prefix `--graphy-editor-menu-` with `background`, `text`, `border`, `radius`, `shadow`, `padding`, `title-font`, `min-width` or `max-width`. These take precedence over shared properties.

Selection outlines use the spec's `editOutline` style target. Style both states together, or use `.hover` and `.selected` separately:

```tsx theme={null}
styles({
  defaults: [
    style.editOutline({ stroke: '#0f62fe', dashArray: [4, 2] }),
    style.editOutline.selected({ strokeWidth: 2, offset: 4 }),
  ],
});
```

Supported properties are `stroke`, `strokeAlpha`, `strokeWidth`, `dashArray` (in stroke widths), `backingColor`, `backingAlpha`, `offset` and `cornerRadius`. See [Styling](https://docs.graphy.dev/sdk-next/config/styling.md).

## Related

* [The edit menu](https://docs.graphy.dev/sdk-next/editing/menu.md) — placement, the title, the visibility button and the level selector
* [Commands & history](https://docs.graphy.dev/sdk-next/editing/commands-and-history.md) — the commands a row dispatches, and transient runs
* [Editor panel](https://docs.graphy.dev/sdk-next/editing/editor-panel.md) — the side panel, which draws from the same control registry


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.