Skip to content

Nested Marks

Use __slot__ when a mark should contain parsed child tokens.

const options = [{markup: '**__slot__**'}]

A slot mark receives rendered child tokens as children. Render those children to preserve nested content.

function Bold({children}: {children?: React.ReactNode}) {
return <strong>{children}</strong>
}

Use useMarkInfo() for nesting metadata:

import {useMark, useMarkInfo} from '@markput/react'
function TreeMark({children}: {children?: React.ReactNode}) {
const mark = useMark()
const info = useMarkInfo()
return (
<span data-depth={info.depth} data-mark-key={info.key}>
{info.hasNestedMarks ? children : mark.slot ?? mark.value}
</span>
)
}
PropertyPurpose
addressCore token address for the current parse generation.
depthNesting depth, where top-level marks are 0.
hasNestedMarksWhether any child token is a mark.
keyStable key for the current token path.

Parent and child traversal is intentionally not exposed through useMark(). Core owns token addresses and validates them through the token index.

React and Vue wrap nested slot content in an internal child-sequence host. Custom Mark components should treat children as opaque rendered content and render it exactly once.

function Highlight({children}: {children?: React.ReactNode}) {
return <mark>{children}</mark>
}

Marks can render controls, icons, or layout elements around children:

function TodoItem({children}: {children?: React.ReactNode}) {
return (
<label>
<input type="checkbox" />
{children}
</label>
)
}

Do not inspect DOM child order to infer token identity. Use useMarkInfo() for structure and useMark() for commands.

If a Mark component ignores children, nested content is not rendered. This is valid for value-only marks, but slot marks should render children or explicitly provide a fallback.

function SlotMark({children}: {children?: React.ReactNode}) {
const mark = useMark()
const info = useMarkInfo()
return <span>{info.hasNestedMarks ? children : mark.slot}</span>
}