The <d3-polytree-editor> custom element — a framework-free, shadow-DOM wrapper around the
@d3-polytree/editor. It hosts
the editor with no engine fork, reflects the serialized .pfdn document as a value property /
attribute, participates in <form>s via ElementInternals (feature-gated), and emits a change
CustomEvent on every committed edit. All styling is inlined into the shadow root, so it renders
identically wherever you drop it.
▶ Live demo in Storybook.
pnpm add @d3-polytree/element d3-selection d3-zoom d3-transition d3-scale d3-axis d3-dragShips ESM + CJS + .d.ts and a self-contained UMD bundle (dist/element.umd.js). Importing the
package registers the tag as a side effect, and all styling is inlined into the shadow root (no CSS
import). The six D3 v7 slices are peer dependencies (inherited from the wrapped @d3-polytree/editor
→ core) for the ESM/CJS build; the UMD bundle inlines them, so a plain <script> drop-in needs
nothing extra.
<script type="module">
import '@d3-polytree/element'; // registers <d3-polytree-editor>
</script>
<d3-polytree-editor style="display:block; width:100%; height:600px;"></d3-polytree-editor>Seed it with a document via the value attribute, and read edits back off the change event:
<d3-polytree-editor id="ed" value="<pfdn:diagram …>…</pfdn:diagram>"></d3-polytree-editor>
<script type="module">
import '@d3-polytree/element';
const el = document.getElementById('ed');
el.addEventListener('change', (e) => console.log('new .pfdn:', e.detail));
</script>The element is form-associated (static formAssociated = true) via ElementInternals, so its
current .pfdn document is submitted with the form under the element's name — no hidden input, no
glue code:
<form>
<d3-polytree-editor name="diagram"></d3-polytree-editor>
<button type="submit">Save</button>
</form>Where ElementInternals is unavailable (older engines, jsdom), form association degrades gracefully
and the rest of the element keeps working.
Auto-registration happens on import. To register under your own control (e.g. after feature-checks), call the named export:
import { defineD3PolytreeEditor } from '@d3-polytree/element';
defineD3PolytreeEditor(); // idempotent — guards HMR / repeated evaluation| Member | Type | Description |
|---|---|---|
value |
property / attribute | The current diagram as a .pfdn XML string; setting it reloads the editor (echo-guarded so the element never reloads on its own emitted change). |
exportSVG() |
method | The current SVG with the shadow-scoped CSS inlined, pinned to the light theme so exports stay theme-invariant. |
change |
CustomEvent<string> |
Fired on every committed edit; detail is the new .pfdn. Bubbles and crosses the shadow boundary (composed). |
D3PolytreeEditorElement |
class | The element class, if you need to subclass or reference it. |
defineD3PolytreeEditor() |
function | Idempotent tag registration. |
The element gives itself tabindex="0" (so keyboard undo/redo reaches the editor) and delegates focus
into the shadow root. The editor subscription survives importDiagram reboots, so external value
changes never drop the change wiring.
Reach for this adapter when you want the editor in any framework (or none) through a standard DOM
element and form semantics. For an idiomatic React binding with imperative ref handles, use
@d3-polytree/react instead.
MIT © David Castillo