Add data attributes to your rendered HTML to enable progressively richer visual editing:
Example of a fully annotated slide block:
If you can't modify the markup (e.g., using a 3rd party component library), use comment syntax to specify block attributes:
block-uid=xxxedit-text=title(.card-title)<!-- /hydra --> marks end of scope<!-- hydra block-uid=xxx /--> applies only to next sibling elementSupported attributes: block-uid, block-readonly, edit-text, edit-link, edit-media, block-add
Add data-linkable-allow to elements that should navigate during edit mode (paging links, facet controls, etc.):
Every data-edit-* attribute — data-edit-text, data-edit-link, data-edit-media — takes a Unix-style field path, resolved the same way for all three. A path has two independent axes:
Which block (the leading part):
.. always steps up one block — never an object or region level (see below).
Where inside the block (/ descends objects):
field to a nested field (the key mirrors the storage path, block.content.headline)
The two compose: ../content/headline is "the parent block, its content.headline". / descends objects only — a region (object_list / blocks_layout) or a value is the end of a path (a region's children are separate blocks with their own data-block-uid).
This lets fixed parts of the page (headers), parent-block fields, and fields grouped inside an object all be edited in place, with one addressing model.
Add data-block-readonly (or <!-- hydra block-readonly --> comment) to disable inline editing for all fields inside an element:
Or using comment syntax:
When rendering Slate nodes to DOM, your renderer must follow these rules for data-node-id:
p, strong, em, etc.) must have data-node-id matching the Slate node's nodeIddata-node-id as the inner elementhydra.js uses node-ids to map between Slate's data model and your DOM. When restoring cursor position after formatting changes, it walks your DOM counting Slate children.
A slate field's value is an array, but it always holds exactly one top-level node — a single paragraph, heading, list, or blockquote. Inline content (bold, links, …) lives in that node's children.
Editing can transiently produce more than one top-level node — pasting multiple paragraphs, pressing Enter, or a Backspace that demotes a list item to a paragraph ([ul, p]). Hydra normalizes that immediately:
value of a slate block, each extranode becomes its own slate block, inserted after the original in the same container (blocks_layout or object_list). This is how pressing Enter in a text block produces a new block.
non-slate block (e.g. a slateTable cell's value), a slate field nested on a widget: 'object' (content/headline), or a container that's full or in table mode — the extra nodes' content merges back into the first node. No text is lost.
A frontend renderer can therefore always assume one top-level node per slate field; it never has to handle a multi-node value.
Slate data structure (value is an array but always contains a single root node):
Renderer:
Usage: