Markdown Editor
A live markdown editor where a textarea bound to a form field renders a real-time preview via react-markdown. Because the form field is a MobX observable, every keystroke immediately updates the preview.
🔗 Live Demo: Markdown Editor
📁 Source: FormMarkdown.tsx
📁 Setup: markdown.ts
Concept
This demo showcases the simplest possible reactive pattern: a single field whose value is bound to a <textarea> for editing and simultaneously read by a <ReactMarkdown> component for preview. No onChange wiring, no useEffect — the MobX observable chain handles everything automatically.
Form Setup
A single field content holds the entire markdown string. The initial value is imported from a markdown data file:
import * as markdownData from '../data/example.md';
const fields = {
content: {
label: 'Markdown Text',
value: markdownData.default,
},
};
Component Walkthrough
The textarea
The <Textarea> component calls field.bind() which spreads name, value, onChange, and onBlur onto the textarea element. Every keystroke calls field.onChange(e), which updates the MobX observable:
<Textarea field={form.$('content')} />
Internally, the <Textarea> component (similar to <Input>) simply does:
<textarea {...field.bind({ className: 'form-input' })} />
The live preview
<ReactMarkdown> reads form.$('content').value — a MobX observable. Because the component is wrapped in observer(), it re-renders whenever content.value changes:
<ReactMarkdown>{form.$('content').value}</ReactMarkdown>
Separator
A <div className="divider" /> separates the editor from the preview, making the split layout clear.
The reactive chain
Keystroke → field.onChange(e) → MobX sets content.value
→ observer re-renders textarea (new value displayed)
→ observer re-renders ReactMarkdown (preview updated)
There is no explicit state, no useEffect, no manual DOM manipulation. MobX handles the entire pipeline.
Key Takeaways
- Single field: One field is enough for the editor + preview pattern.
- Automatic reactivity:
observer()catches every MobX change — the preview updates on every keystroke. - No wiring:
field.bind()handles all event handlers on the textarea. - Any preview library works: Replace
react-markdownwith any renderer (HTML sanitizer, code highlighter, MathJax, etc.). - Custom converters: For non-string data, use
input/outputconverter functions (see Converters).