docs/solutions/best-practices/2026-03-31-transforminitialvalue-should-replace-normalizeinitialvalue-with-a-compat-layer.md
transformInitialValue should replace normalizeInitialValue with a compat layerThe plugin hook name normalizeInitialValue was muddy. It sounded like Slate
runtime normalization, but the hook actually existed to transform the initial
editor value before the editor was ready.
That naming drift matters because it nudges people toward imperative mutation when the better long-term seam is a value-to-value transform.
normalizeInitialValue meant:
editor.childrenAdd the better name first, then let the old one decay.
transformInitialValuetransformInitialValue is now the preferred plugin hook name. It says what the
hook actually does: transform the initial value.
The hook accepts the same context and must return the next value:
type TransformInitialValue = (ctx: {
editor: SlateEditor;
value: Value;
}) => Value;
normalizeInitialValue as a compatibility aliasLegacy plugins still work. The init pipeline resolves hooks like this:
const transformInitialValue =
plugin.transformInitialValue ?? plugin.normalizeInitialValue;
That keeps the old hook name alive without freezing the new API in the past:
transformInitialValue must return the next valuenormalizeInitialValue may either return the next value or mutate
value in placetransformInitialValue winsThe nodeId option got the same treatment:
initialValueIdsnormalizeInitialValuefalse -> 'if-needed'true -> 'always'null -> falseBuilt-in plugin surfaces that own this behavior should use the new name now. That includes:
nodeId and tableIt fixes the naming without forcing a fake migration emergency.
The new hook name makes the desired design direction obvious:
The compatibility layer keeps the old name working while still making the new contract obvious and preferable.