HandwritingRecognition
Turn strokes drawn with a finger, a stylus or a mouse into text using a model already on the device - nothing downloaded, nothing sent anywhere.
@inject Bit.Butil.HandwritingRecognition handwritingMDN reference
Warning:
Chromium, and only where the OS has a model
Niche and Chromium-only, and even there it depends on the operating system shipping a model for
the language.
IsSupported only says the API exists -
QuerySupport is the check that matters, because it asks about your language.
QuerySupport answers per feature rather than as one yes or no: a runtime that supports handwriting still says no to a language it has no model for, and no to hints it doesn't implement.
@inject Bit.Butil.HandwritingRecognition handwriting
var support = await handwriting.QuerySupport(["en"], alternatives: true, textContext: false);
if (support?.Languages is true)
{
// this device can recognize English
}
Live sample
support check output
Results will appear here when you interact with the samples.
Collect the strokes yourself from pointer events - one stroke per pointer-down to pointer-up, because stroke boundaries carry meaning: a 't' is two strokes and an 'l' is one. Then hand the whole lot over. Passing each point's timestamp is optional but materially improves the result, since writing speed and pauses are part of how the recognizer separates characters.
var strokes = new List<HandwritingStroke>(); // filled from pointer events
// milliseconds since the first point of the first stroke - one clock for the whole drawing:
// new HandwritingPoint(e.OffsetX, e.OffsetY, elapsedMilliseconds)
var candidates = await handwriting.Recognize(
[.. strokes],
languages: ["en"],
recognitionType: "text",
inputType: "mouse",
alternatives: 3);
var best = candidates.FirstOrDefault();
Live sample
recognition output
Results will appear here when you interact with the samples.
API reference
Member
Signature
Description
IsSupported
ValueTask<bool> IsSupported()True when the runtime exposes navigator.createHandwritingRecognizer. Says nothing about whether a model for your language is installed.
QuerySupport
ValueTask<HandwritingSupport?> QuerySupport(string[]? languages = null, bool alternatives = true, bool textContext = false)Whether this device can recognize these languages, and whether it implements the optional hints. Null when there is no handwriting recognition at all.
Recognize
ValueTask<string[]> Recognize(HandwritingStroke[] strokes, string[]? languages = null, string recognitionType = "text", string inputType = "mouse", string? textContext = null, int alternatives = 3)Recognizes text from strokes, best candidate first. Empty when there is no model, the feature is off, or there is nothing readable.
HandwritingStroke
PointsOne stroke: the points sampled between a pointer going down and coming back up.
HandwritingPoint
X | Y | TOne sampled point. T - milliseconds since the first point of the drawing, one clock across every stroke - is optional but improves the result.
HandwritingSupport
Languages | Alternatives | TextContextWhat the device's recognizer will actually do.