Overview
In WASM you do not “implement IME” for web: the OS/IME draws the candidate window and inserts text through the browser’s editing pipeline. Your integration work is event ordering, commit boundaries, and keeping one source of truth during an unfinished composition.
This site’s scenarios on composition,
beforeinput, and mobile keyboards apply equally when
the backing model is Rust.
The browser owns IME
Calls across the JS↔WASM boundary should not assume you can sample
the “final character” on every keydown: during composition, partial
text is provisional. Pushing provisional state into Rust on
every compositionupdate can work but increases copies
and race risk with layout.
Treat compositionend (and equivalent commit signals) as the primary point to commit stable text into your Rust model—unless you have a deliberate streaming design and handle cancellation.
Composition lifecycle
-
compositionstart— mark an “IME session” in your controller; pause structural merges that assume committed text. -
compositionupdate— DOM shows intermediate glyphs; optional lightweight mirror into WASM for preview features. -
compositionend— commit; reconcile selection offsets in UTF-8/UTF-16 aware code (JS strings are UTF-16; RustStringis UTF-8—index mismatches are a classic bug).
Pair with beforeinput where available; cancellation
semantics differ by browser—see Editor → Input handling.
Syncing a Rust model
Practical strategies:
- DOM truth during composition: WASM holds structural doc; JS keeps ephemeral composition text in the DOM until commit—then send one patch across the boundary.
- Op log from committed input only: WASM applies operations for committed codepoints; composition preview stays out of CRDT until commit (simpler for Yjs/Yrs interop).
- Full mirror: stream updates—only if you measure boundary cost and handle rollback on cancel.
Mobile & platform variance
Mobile keyboards differ in when composition events fire, how backspace behaves in Hangul/Japanese, and how WebView wrappers behave. Your WASM core cannot abstract that away—you need the same empirical testing as any web editor.
Related: Editor → Mobile support.
Wasm guides
Editing approaches
contenteditable + WASM: source of truth, event order, DOM↔model loop, normalization, and when to call Rust.
JS ↔ WASM boundary
Strings, copies, batched ops, async vs input events, and keeping the hot path cheap.
Clipboard & input routing
beforeinput, paste, routing decisions in JS vs sanitization in WASM.
Tooling, bundle & workers
wasm-pack, wasm-opt, code splitting, Web Workers, COOP/COEP and threads.
Collaboration & CRDT (WASM)
Yrs/y-crdt, bridging to Yjs, snapshots vs update streams with an editor host.
Selection, Range & offsets
UTF-16 vs UTF-8 indices, Selection/Range in JS, mapping to a Rust model and getTargetRanges.
Undo & redo model
Browser undo stack vs model history, programmatic DOM, and WASM-hosted transactions.
Accessibility (WASM host)
Roles, focus, screen readers when the editable surface is still the browser.
Testing & debugging
E2E, profiling the JS↔WASM boundary, reproducing IME and paste in CI.
Security & deployment
CSP, SRI, module integrity, and hosting WASM next to contenteditable.