A release-note tool starts with a blank source pane. The instruction “Write the change summary here” should help the author begin, but it must never become a sentence in the saved release note. An initial document value and an empty-state hint have different consequences.
Supply a hint and a persistent label
For an initialized browser application using compatible CodeMirror 6 packages:
<p id="release-source-label">Release-note source</p>
<div id="release-source"></div>
<p id="release-source-help">
Include the affected feature and what changed for its users.
</p>
import { EditorView, placeholder } from '@codemirror/view';
const view = new EditorView({
doc: '',
extensions: [
placeholder('Write the change summary here'),
EditorView.contentAttributes.of({
'aria-labelledby': 'release-source-label',
'aria-describedby': 'release-source-help'
})
],
parent: document.querySelector('#release-source')
});
Include your application's normal editing extensions alongside these. The snippet mounts an empty editor, but does not add HTML language support, a save service, or release approval rules.
The persistent label identifies the field after the first character hides the hint. The help paragraph remains available while the person writes. The current placeholder implementation supplies aria-placeholder for a string hint and hides the decorative placeholder widget from the accessibility tree. A placeholder still does not replace a proper field name or a required instruction outside the editor.
Keep the document genuinely empty
Read the saved source from the model:
const releaseSource = view.state.doc.toString();
Before anyone types, this should be an empty string even though the hint is visible. Never scrape .cm-content.innerText to collect a document: decorations and rendering details belong to the view. The same model-versus-view boundary matters when source ranges are folded.
The implementation tests document length, not whether trimmed text is empty. A space or newline is still document content, so it can hide the hint. If a tool treats whitespace-only input as missing, implement that rule in its validation and explain the result to the author. Avoid repeatedly clearing whitespace merely to make a placeholder reappear.
Style the hint without weakening ordinary text
An editor theme can target the placeholder class:
const emptyHintTheme = EditorView.theme({
'.cm-placeholder': {
color: '#59656b',
fontStyle: 'italic'
}
});
Include emptyHintTheme in the same editor's extensions. Check the chosen color against the actual editor background; a color suitable for a light page may be unreadable in a dark editor. Keep ordinary document text styling separate so the author's first sentence does not inherit the hint's appearance. The theme-switching guide covers changing an existing editor's configured theme.
For ordinary hints, a string is sufficient. The API can also accept an element or a function returning one, but an empty-state message does not need interactive controls placed inside a decoration. Put actions such as “Load approved example” in the surrounding application and make their document changes explicit.
Check the empty, typed, and cleared states
Open the editor with doc: ''. Confirm the visible hint and inspect the source string: its length should be zero. Type Updated collection instructions. and verify that the hint disappears while that exact sentence becomes the document. Clear all the text and confirm the hint returns without becoming part of the model.
Repeat with a single space to see the length-based behavior. Check that the persistent label and help text remain visible in each state. Finish by saving through the application's normal path and inspecting the stored source. A hint that was never part of the document should never appear in the released note.