React Integration
WriteTrack provides a React hook for plain <textarea>, <input>, and contenteditable elements. If you’re using a rich text editor (TipTap, CKEditor, Lexical, etc.), use the editor-specific extension instead — it handles lifecycle management through the editor’s plugin system.
Installation
Section titled “Installation”npm i writetrackpnpm add writetrackyarn add writetrackbun add writetrackReact is an optional peer dependency - non-React users won’t have it in their bundle.
Basic Usage
Section titled “Basic Usage”import React, { useRef } from 'react';import { useWriteTrack } from 'writetrack/react';
export function ResponseForm() { const textareaRef = useRef<HTMLTextAreaElement>(null); const { tracker, isTracking } = useWriteTrack(textareaRef);
const handleSubmit = (e: React.FormEvent) => { e.preventDefault();
if (tracker) { const data = tracker.getData(); console.log('Session data:', data); } };
return ( <form onSubmit={handleSubmit}> <textarea ref={textareaRef} placeholder="Type your response..." /> {isTracking && <p>Tracking keystrokes...</p>} <button type="submit">Submit</button> </form> );}API Reference
Section titled “API Reference”useWriteTrack
Section titled “useWriteTrack”function useWriteTrack( ref: RefObject<HTMLElement | null>, options?: UseWriteTrackOptions): UseWriteTrackReturn;Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
ref | RefObject<HTMLElement> | React ref attached to the input element |
options.license | string | WriteTrack license key |
options.userId | string | User identifier included in metadata |
options.contentId | string | Content identifier included in metadata |
options.metadata | Record<string, unknown> | Additional metadata |
options.autoStart | boolean | Auto-start tracking when element mounts (default: true) |
options.wasmUrl | string | URL to WASM binary for analysis |
options.persist | boolean | Enable IndexedDB session persistence (requires contentId) |
options.analysis | boolean | Subscribe to real-time analysis events (requires WASM) |
options.onTick | (data: { activeTime: number; totalTime: number; tracker: WriteTrack }) => void | Callback fired every ~1s with active session time and tracker instance |
options.onReady | (tracker: WriteTrack) => void | Callback fired when tracker is ready |
Callbacks (onTick, onReady) are always up to date — no need for useCallback or manual refs.
Return Value
Section titled “Return Value”| Property | Type | Description |
|---|---|---|
start | () => void | Start tracking (if autoStart was false) |
stop | () => void | Stop tracking |
reset | () => void | Reset tracker and clear state |
isTracking | boolean | Whether tracker is active |
tracker | WriteTrack | null | Underlying WriteTrack instance |
isReady | boolean | Whether tracker has initialised |
analysis | SessionAnalysis | null | Latest analysis result (when analysis: true) |
error | Error | null | Latest error from WASM or initialisation |
Examples
Section titled “Examples”With Real-Time Analysis
Section titled “With Real-Time Analysis”import { useRef } from 'react';import { useWriteTrack } from 'writetrack/react';
function AnalyzedForm() { const textareaRef = useRef<HTMLTextAreaElement>(null); const { analysis, isReady, error } = useWriteTrack(textareaRef, { analysis: true, });
return ( <div> <textarea ref={textareaRef} /> {!isReady && <p>Initialising...</p>} {error && <p>Error: {error.message}</p>} {analysis && <p>Origin: {analysis.contentOrigin.indicator.code}</p>} </div> );}Manual Start/Stop
Section titled “Manual Start/Stop”import React, { useRef } from 'react';import { useWriteTrack } from 'writetrack/react';
export function ControlledForm() { const inputRef = useRef<HTMLInputElement>(null); const { start, stop, tracker, isTracking } = useWriteTrack(inputRef, { autoStart: false, });
return ( <div> <input ref={inputRef} type="text" />
<button onClick={isTracking ? stop : start}> {isTracking ? 'Stop' : 'Start'} Tracking </button>
<button onClick={() => tracker && console.log(tracker.getData())}> Get Data </button> </div> );}With Multiple Inputs
Section titled “With Multiple Inputs”Call useWriteTrack once per field you want to track. Each hook manages its own independent tracker instance.
function MultiFieldForm() { const titleRef = useRef<HTMLInputElement>(null); const bodyRef = useRef<HTMLTextAreaElement>(null);
const title = useWriteTrack(titleRef, { contentId: 'title' }); const body = useWriteTrack(bodyRef, { contentId: 'body' });
const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const fields = [ { name: 'title', data: title.tracker?.getData() }, { name: 'body', data: body.tracker?.getData() }, ]; console.log('Session data:', fields); };
return ( <form onSubmit={handleSubmit}> <input ref={titleRef} placeholder="Title (tracked)" /> <textarea ref={bodyRef} placeholder="Body (tracked)" /> <button type="submit">Send</button> </form> );}TypeScript
Section titled “TypeScript”import type { UseWriteTrackReturn, UseWriteTrackOptions,} from 'writetrack/react';