@web-ai-sdk/proofreader
v0.6.0
Published
Building block for the Web's Built-in Proofreader API (Chrome)
Maintainers
Readme
@web-ai-sdk/proofreader
Building block for the Web's Built-in Proofreader API. Corrects grammar, spelling, and punctuation and returns per-issue corrections with offsets, plus session reuse and opt-in result caching.
Docs: https://web-ai-sdk.dev/docs/guides/proofreader/ · React: useProofreader
Status
The Proofreader API is in an origin trial in Chrome 141 to 145, behind chrome://flags/#proofreader-api-for-gemini-nano on localhost (chrome://flags/#optimization-guide-on-device-model must also be enabled). In Edge it's a developer preview in Canary/Dev 142+ behind "Proofreader API for Phi mini". On any other browser this library is a no-op for the React hook (it stays in "unavailable"). The vanilla proofread() throws ProofreaderUnavailableError so callers can branch explicitly.
The API is English-only today. expectedInputLanguages accepts an array, but a request for an unsupported language causes the underlying create() to reject (surfaced here as ProofreaderUnavailableError); pass ["en"] or omit it.
Install
pnpm add @web-ai-sdk/proofreader
# or: npm i @web-ai-sdk/proofreader / bun add @web-ai-sdk/proofreaderThe React adapter ships as a subpath export, with no extra install. react is a peer dependency only when you import the /react entry.
Vanilla TypeScript / DOM
import { proofread } from "@web-ai-sdk/proofreader";
const result = await proofread({
input: "I seen him yesterday at the store, and he bought two loafs of bread.",
expectedInputLanguages: ["en"],
});
console.log(result.output?.correctedInput);
for (const c of result.output?.corrections ?? []) {
console.log(c.startIndex, c.endIndex, "→", c.correction);
}result.output is null when the input is empty; otherwise correctedInput is the fully corrected text and corrections is the list of per-issue edits with offsets into the original input.
React
import { useProofreader } from "@web-ai-sdk/proofreader/react";
export function GrammarCheck({ text }: { text: string }) {
const { status, output } = useProofreader({ input: text });
if (status === "unavailable") return null;
if (status === "loading") return <p>Checking…</p>;
return <p>{output?.correctedInput}</p>;
}State machine: idle | loading | done | unavailable. There is no streaming; proofread() resolves once. fromCache is true when the result came back without invoking the model.
API
proofread(options): Promise<ProofreadResult>
interface ProofreadOptions {
input: string;
expectedInputLanguages?: readonly string[];
monitor?: (m: CreateMonitor) => void;
cache?: "session" | "local" | { get, set };
cacheKey?: string;
signal?: AbortSignal;
}
interface ProofreadCorrection {
startIndex: number; // inclusive offset into the original input
endIndex: number; // exclusive offset into the original input
correction: string; // suggested replacement
type?: string; // not emitted by Chrome's current build
explanation?: string; // not emitted by Chrome's current build
}
interface ProofreadOutput {
correctedInput: string;
corrections: ProofreadCorrection[];
}
interface ProofreadResult {
output: ProofreadOutput | null;
cached: boolean;
}isAvailable(): boolean
Feature-detect helper.
checkAvailability(options?): Promise<ProofreaderAvailability | null>
Forwards to the spec's availability() call. Returns null if the global is missing or the call throws.
clearProofreaderSessions(): void
Drop every cached proofreader session. Sessions live for the tab lifetime by default.
Rendering corrections
The corrections offsets index into the original input, so you can highlight each error in place by slicing between offsets:
let cursor = 0;
const spans: Array<{ text: string; error: boolean }> = [];
for (const c of output.corrections) {
if (c.startIndex > cursor)
spans.push({ text: input.slice(cursor, c.startIndex), error: false });
spans.push({ text: input.slice(c.startIndex, c.endIndex), error: true });
cursor = c.endIndex;
}
if (cursor < input.length)
spans.push({ text: input.slice(cursor), error: false });License
MIT © Beto Muniz
