> ## 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.

# Without a bundler

A plain HTML page can use editing without a build step. The npm package includes two standalone ES module bundles, available through jsDelivr:

* `dist/index.browser.mjs` — the read-only renderer and the builders.
* `dist/editable.browser.mjs` — the same, plus the editor and the commands.

Each bundle includes its dependencies except React and React DOM, which the page supplies through an import map. Styles load automatically; no stylesheet link is needed.

Use only the editable bundle for a page that edits. It includes all read-only exports; loading both bundles duplicates the renderer.

## The import map

Point `@graphysdk/react` at the editable bundle and React at jsDelivr's ESM builds:

```html theme={null}
<script type="importmap">
  {
    "imports": {
      "react": "https://cdn.jsdelivr.net/npm/react@19.2.0/+esm",
      "react/jsx-runtime": "https://cdn.jsdelivr.net/npm/react@19.2.0/jsx-runtime/+esm",
      "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@19.2.0/+esm",
      "react-dom/client": "https://cdn.jsdelivr.net/npm/react-dom@19.2.0/client/+esm",
      "@graphysdk/react": "https://cdn.jsdelivr.net/npm/@graphysdk/react@<version>/dist/editable.browser.mjs"
    }
  }
</script>
```

With this map, import both `GraphProvider` and `EditableGraphRenderer` from `@graphysdk/react` inside a `<script type="module">`. Unlike the npm setup, this uses no `/editable` subpath.

> [!WARNING]
>
> Replace `<version>` with a released SDK version. Pin exact versions when
> publishing, and keep all four React and React DOM entries on the same version
> to avoid duplicate React instances.

## A page that edits

This page adds an Edit toggle, Undo and Redo buttons, and a Copy spec button. It uses `createElement` to render React without JSX.

```html theme={null}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Editable chart</title>
    <script type="importmap">
      {
        "imports": {
          "react": "https://cdn.jsdelivr.net/npm/react@19.2.0/+esm",
          "react/jsx-runtime": "https://cdn.jsdelivr.net/npm/react@19.2.0/jsx-runtime/+esm",
          "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@19.2.0/+esm",
          "react-dom/client": "https://cdn.jsdelivr.net/npm/react-dom@19.2.0/client/+esm",
          "@graphysdk/react": "https://cdn.jsdelivr.net/npm/@graphysdk/react@<version>/dist/editable.browser.mjs"
        }
      }
    </script>
  </head>
  <body>
    <div id="root"></div>
    <script type="module">
      import { createElement, useRef, useState } from 'react';
      import { createRoot } from 'react-dom/client';
      import {
        createSpec,
        EditableGraphRenderer,
        geom,
        GraphProvider,
        pipe,
        scale,
        useGraphHistoryShortcuts,
      } from '@graphysdk/react';

      const data = {
        columns: [{ key: 'month' }, { key: 'revenue' }],
        rows: [
          { month: 'Jan', revenue: 120 },
          { month: 'Feb', revenue: 150 },
          { month: 'Mar', revenue: 90 },
        ],
      };

      const spec = pipe(
        createSpec({ x: 'month', y: 'revenue' }),
        geom.bar(),
        scale.x(),
        scale.y()
      );

      function Editor() {
        const [mode, setMode] = useState('readonly');
        const handleRef = useRef(null);
        const latestSpec = useRef(spec);
        useGraphHistoryShortcuts(handleRef);

        const editing = mode === 'edit';
        const toggleMode = () => setMode(editing ? 'readonly' : 'edit');
        const undo = () => handleRef.current?.undo();
        const redo = () => handleRef.current?.redo();
        const copySpec = () =>
          navigator.clipboard.writeText(JSON.stringify(latestSpec.current));

        return createElement(
          'div',
          null,
          createElement(
            'button',
            { onClick: toggleMode },
            editing ? 'Done' : 'Edit'
          ),
          createElement('button', { onClick: undo }, 'Undo'),
          createElement('button', { onClick: redo }, 'Redo'),
          createElement('button', { onClick: copySpec }, 'Copy spec'),
          createElement(
            'div',
            { style: { height: 400 } },
            createElement(
              GraphProvider,
              {
                spec,
                data,
                handleRef,
                onSpecChange: (next) => (latestSpec.current = next),
              },
              createElement(EditableGraphRenderer, { mode })
            )
          )
        );
      }

      createRoot(document.getElementById('root')).render(createElement(Editor));
    </script>
  </body>
</html>
```

`onSpecChange` updates `latestSpec` after each committed edit, undo or redo. Copy spec serializes that value as JSON; pass the parsed JSON back as `spec` to restore the chart. Clipboard access requires HTTPS or localhost.

The ref keeps the latest spec without triggering a React render. Using state and passing the exact `onSpecChange` value back as `spec` also preserves history. See [Saving the chart](https://docs.graphy.dev/sdk-next/editing/commands-and-history.md#saving-the-chart).

`handleRef` connects the buttons and keyboard shortcuts to the chart. The module-level `spec` and `data` stay stable across renders, so toggling edit mode does not recompile the chart.

## Related

* [Overview](https://docs.graphy.dev/sdk-next/editing/index.md) — modes, install and the bundled setup
* [Commands & history](https://docs.graphy.dev/sdk-next/editing/commands-and-history.md) — `handleRef`, undo and redo, the shortcuts
* [Serializable spec](https://docs.graphy.dev/sdk-next/concepts/serializable-spec.md) — what `JSON.stringify` on a spec gives you


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