Inkspan treats keyboard and assistive-technology behavior as part of its public product contract, not as demo-only polish.
- The editable ProseMirror region is exposed as a multiline textbox.
- Hosts can provide a string accessible name through
ariaLabelor reference visible labels throughariaLabelledBy. A non-emptyariaLabelledBytakes precedence so the visible host label remains the source of truth. languageTagplaces a trimmed BCP 47langvalue on the editable document surface so browsers, spellcheckers, and assistive technologies can apply the correct language rules. Blank values are omitted rather than declaring an unknown language.textDirectionmaps to the HTMLdirstatesltr,rtl, orautoand establishes the base writing direction for authored content.ariaDescribedByassociates instructions, constraints, or contextual help with the editor.ariaErrorMessage,ariaInvalid, andariaRequiredexpose host-owned validation state without coupling Inkspan to a particular form library.- Read-only mode removes editing actions while preserving document readability and sets
aria-readonly="true"; switchingeditable, language, direction, or any accessibility prop after mount updates the existing editor DOM without recreating document state. - Informative images support authored alternative text; decorative images are serialized with an explicit empty
altvalue. A successful toolbar file conversion requires the author to make that informative-versus-decorative decision before insertion rather than silently treating omission as decorative intent.
<form method="post" action="/messages">
<h2 id="message-body-label">Message body</h2>
<p id="message-body-help">Include the decision and supporting evidence.</p>
<p id="message-body-error">A message body is required.</p>
<CwlEditor
mode="markdown"
formFieldName="message_body"
formResetValue="# New message"
onFormReset={() => clearHostValidation()}
languageTag="ko-KR"
textDirection="ltr"
ariaLabelledBy="message-body-label"
ariaDescribedBy="message-body-help"
ariaErrorMessage="message-body-error"
ariaInvalid={hasBodyError}
ariaRequired
editable={!isArchived}
/>
<button type="submit">Send</button>
<button type="reset">Reset</button>
</form>When formFieldName is supplied, Inkspan renders a native hidden input whose live value is the current document serialized in mode. The field participates in FormData, ordinary browser submission, and form-library workflows that read native controls. formId associates the field with a form elsewhere in the document, and formFieldDisabled excludes it from submission using the native disabled-control rule. The same serialization props are inherited by CollaborativeCwlEditor; its field follows Yjs-backed document changes rather than a static value prop.
Inkspan writes the hidden input's native value synchronously inside each document-changing TipTap transaction. A host may therefore call an imperative editor method and immediately construct FormData, invoke a native submit path, or let the browser construct the form entry list in the same task without waiting for a React rerender. Selection-only transactions do not serialize or rewrite the field. This guarantee concerns the current client-side form value only; it does not replace host validation, authorization, persistence, or request-size enforcement.
The hidden field is a submission bridge, not a second editable control. It is absent from the accessibility tree and does not duplicate the textbox name, description, or validation state. Hidden inputs are barred from native constraint validation, so ariaRequired, ariaInvalid, visible error copy, business validation, and focus recovery remain host responsibilities.
Native form reset is opt-in for standalone editor state. When formResetValue is supplied to CwlEditor, Inkspan interprets it in the active mode and applies it only after the associated form's cancelable reset event completes without preventDefault(). onFormReset then receives the stable TipTap editor and native reset event after the configured reset document has been applied. With only onFormReset, Inkspan reports the allowed reset without mutating the document, allowing controlled hosts to update value or invoke their own domain-specific reset workflow. Controlled hosts that use formResetValue must continue accepting the resulting onChange value as their source of truth.
Reset integration does not require a submission field name. When either supported reset prop is configured without formFieldName, Inkspan renders an unnamed hidden form owner so it can observe the enclosing form or the form selected by formId; because the control has no name, it contributes no entry to FormData or ordinary submission.
A canceled reset leaves document state untouched and does not call onFormReset. CollaborativeCwlEditor intentionally excludes and rejects formResetValue: a local browser form action cannot silently replace shared Yjs state. Collaborative hosts may use onFormReset to observe an allowed reset, confirm authorization and user intent, and then perform an explicit shared-document transaction through their own collaboration, transport, and persistence policy. Omitting reset props preserves entirely host-owned reset semantics.
For Arabic, Persian, Hebrew, or another right-to-left document, use the corresponding BCP 47 language tag and textDirection="rtl". Use textDirection="auto" only when the host intentionally delegates base-direction detection to the browser; the HTML algorithm uses the first strongly directional character and is not a substitute for document-level language knowledge.
ariaLabelledBy and ariaDescribedBy accept space-separated ID references. Blank references are omitted rather than emitted as broken relationships. ariaInvalid accepts the WAI-ARIA textbox values true, false, grammar, and spelling. The same language, direction, form-serialization, reset-observation, and ARIA props are inherited by CollaborativeCwlEditor; automatic reset values are standalone-only, and presence and connection announcements remain a separate polite status region.
Inkspan does not infer a document language, translate validation copy, or choose writing direction from user identity because those decisions belong to the host's document metadata and locale policy. Inkspan also does not render validation copy because business rules, localization, submit timing, and error recovery belong to the host. Hosts should set aria-invalid="true" only after detecting an actual input error and should keep the referenced error text visible and actionable.
Form values are ordinary client-controlled input. Hidden inputs are visible and mutable through developer tools, so servers must authorize the target document, validate the submitted serialization, reapply size limits, and never treat the field as a trust or secrecy boundary. Inline base64 images can make request bodies large; CWL and naruon gateways should align reverse-proxy, application, and persistence limits with the configured image policy before enabling native submission. Reset values are likewise client-side presentation state and must not grant authorization, erase protected server state, or bypass collaborative permissions.
The built-in formatting toolbar implements the horizontal composite-toolbar pattern from the WAI-ARIA Authoring Practices toolbar specification and its editor toolbar example.
Keyboard behavior:
| Key | Behavior |
|---|---|
Tab / Shift+Tab |
Enter or leave the toolbar through one remembered tab stop |
Right Arrow |
Move to the next enabled control, wrapping at the end |
Left Arrow |
Move to the previous enabled control, wrapping at the beginning |
Home |
Move to the first enabled control |
End |
Move to the last enabled control |
Enter / Space |
Invoke the focused native button |
Disabled table, image, undo, and redo controls are skipped by directional navigation. When the remembered control becomes disabled after an editor transaction, the first enabled control becomes the toolbar tab stop.
Toggle controls expose aria-pressed; one-shot command buttons do not claim a pressed state. The toolbar declares horizontal orientation and ships visible :focus-visible styling, including a forced-colors fallback.
After the image file passes the existing local conversion, type, size, and decode policy, the toolbar asks for alternative-text intent before creating the image node. A non-empty response becomes the image alternative text; an explicitly submitted empty response marks the image decorative with alt=""; canceling leaves the document unchanged. Conversion failures continue through onImageError and do not open the alternative-text prompt. The separate Alt control remains available for later corrections when an image is selected.
Shortcuts that the editor already implements are also exposed programmatically with aria-keyshortcuts so assistive technology can discover the same commands that appear in the button titles. Inkspan publishes Control+B Meta+B for bold, Control+I Meta+I for italic, Control+K Meta+K for link editing, Control+Z Meta+Z for undo, and Control+Shift+Z Meta+Shift+Z Control+Y Meta+Y for redo. The redo alternatives reflect Tiptap's configured history and collaboration behavior: both Ctrl/Cmd+Shift+Z and Ctrl/Cmd+Y invoke redo. aria-keyshortcuts describes shortcuts that Inkspan already implements; it does not create keyboard behavior, replace the visible button label, or authorize hosts to intercept those combinations. The explicit values remain Control and Meta rather than a presentation-only Ctrl/Cmd abbreviation because WAI-ARIA defines those modifier tokens and permits a space-separated list of alternatives.
The link shortcut is implemented by Inkspan's editor surface rather than by Tiptap's Link extension: Ctrl/Cmd+K opens the same prompt-driven, safe-link-validated command as the toolbar button. The Link extension itself still provides no default keyboard shortcut. Inkspan therefore exposes Control+K Meta+K on the link toolbar button because the shipped editor surface implements that binding. Hosts remain responsible for application-level shortcut conflicts and must not shadow an advertised command without an equivalent accessible path.
Inkspan cannot determine the complete accessibility of an embedding application. Hosts remain responsible for:
- supplying a valid BCP 47
languageTagthat reflects the authored document, not merely the surrounding application shell; - choosing
textDirectionfrom document metadata and updating it when the document's base direction changes; - marking passages in a different language inside serialized HTML when WCAG language-of-parts conformance is required, because a single editor-level language cannot describe mixed-language spans;
- providing a visible, context-specific label through
ariaLabelledBywhen practical, or a conciseariaLabelwhen no visible label exists; - keeping every
ariaLabelledBy,ariaDescribedBy, andariaErrorMessagetarget present with a descriptive nonnumeric DOM identifier; - choosing meaningful alternative text for informative images and submitting an empty value only when the image is intentionally decorative in its authored context;
- choosing a descriptive
formFieldName, validating submitted content server-side, and aligning request-size limits when native form serialization is enabled; - choosing whether standalone form reset should mutate the document and keeping controlled state synchronized;
- treating collaborative reset callbacks as requests for a separately authorized shared-document operation rather than passing an automatic reset value;
- identifying errors in text, supplying known correction guidance, and synchronizing
ariaInvalidwith the visible validation state; - preserving sufficient contrast when overriding Inkspan CSS variables;
- announcing persistence and network failures in an appropriate live region;
- ensuring surrounding dialogs, forms, and application shortcuts do not trap or steal focus, suppress Inkspan's advertised shortcuts, or bind conflicting actions without an equivalent accessible command;
- testing the integrated workflow with representative browsers, screen readers, zoom levels, scripts, writing directions, input methods, and advertised keyboard shortcuts.
- WCAG 2.2, Success Criterion 1.1.1 Non-text Content — informative non-text content needs an equivalent text alternative, while defined decorative exceptions may use an empty alternative.
- WAI Images Tutorial and Decorative Images guidance — image purpose determines whether meaningful alternative text or an explicit empty alternative is appropriate, so decorative classification remains an author decision.
- WCAG 2.2, Success Criteria 3.1.1 and 3.1.2 — programmatic language identification for the page and language changes within content.
- HTML Living Standard: global
langanddirattributes — language metadata and the enumeratedltr,rtl, andautodirection states. - HTML Living Standard: hidden input state — hidden values, form submission participation, and exclusion from constraint validation.
- HTML Living Standard: form control infrastructure — control naming, external form association, current-value semantics, disabled controls, and form entry construction.
- HTML Living Standard: resetting a form — the bubbling, cancelable reset event and resettable-control algorithm.
- React: queueing state updates — state setters request a later render and React batches updates until event handling completes.
- WAI-ARIA 1.2 textbox role — accessible name, multiline, readonly, required, invalid, description, and error-message states.
- WAI-ARIA 1.2
aria-keyshortcuts— programmatic exposure of implemented shortcuts, exact modifier tokens, plus-separated key combinations, and space-separated alternatives. - Tiptap Undo/Redo extension — the editor's history behavior includes both Shift+Control/Cmd+Z and Control/Cmd+Y redo alternatives.
- Tiptap Collaboration extension — collaborative history provides the same two redo alternatives while host-owned collaboration remains separate from accessibility metadata.
- Tiptap Link extension — the configured link extension provides commands and link behavior but no default keyboard shortcut; Inkspan's editor surface supplies its own
Ctrl/Cmd+Kbinding. - WAI-ARIA APG: Accessible names and descriptions — visible-label preference and
aria-labelledby/aria-describedbyrelationships. - WCAG 2.2, Guideline 3.3 Input Assistance — labels or instructions, textual error identification, and correction suggestions.
- ARIA in HTML — valid readonly semantics for custom contenteditable textboxes.
The TypeScript test suite verifies the single-tab-stop invariant, remembered focus, disabled-control fallback, wrapping arrow navigation, Home/End behavior, toggle semantics, toolbar orientation, exact aria-keyshortcuts exposure for implemented cross-platform formatting/history shortcuts including the editor-surface link binding and both documented redo alternatives, omission of shortcut metadata from controls without a defined shortcut, explicit image-insertion alternative-text intent for informative and decorative images, canceled insertion, no-file behavior, conversion-failure reporting without an alternative-text prompt, later alternative-text editing, accessible-name precedence, blank language and ID-reference omission, lang/dir propagation, validation states, read-only semantics, native form submission, same-task form-entry synchronization, disabled/external form behavior, live serialization-mode changes, imperative replacement, allowed and canceled standalone resets, reset-only form ownership, unrelated-form isolation, callback-only reset handling, queued-reset cleanup, collaborative automatic-reset rejection, collaborative callback-only observation without shared-state mutation, collaborative updates, and live prop updates for standalone and collaborative surfaces under the repository-wide 100% statement/branch/function/line coverage gate.