use-chrome-ai: Hooks for Chrome Built-in AI API'sUse Chrome's Built-in AI API's to build a chat bot with a single hook
JUN 04, 2026 5 MIN READ
Back to blog
Chrome AI React Vue

use-chrome-ai

Core: GitHub · use-chrome-ai

React: React Demo · @use-chrome-ai/react

Vue: Vue Demo · @use-chrome-ai/vue

After playing with Chrome's built-in AI APIs, I wanted a small wrapper that handled the repetitive bits: availability, download progress, streaming, aborts, and session lifecycle and integrated into react easily.

The package shape

The core package is framework-agnostic. The React package exports hooks, and the Vue package exports composables plus the same core factories. None of them ship UI, they just give you a stable state model around the browser APIs.

install.sh
npm i use-chrome-ai
npm i @use-chrome-ai/react
npm i @use-chrome-ai/vue

One-hook chat

The useChat hook allows you access to prompt API and can set up a basic chat bot in one hook.

Chat.tsx
import { useChat } from "@use-chrome-ai/react";

export function Chat() {
  const { messages, input, setInput, send, stop, isStreaming, model } = useChat(
    {
      system: "You are a helpful assistant.",
    },
  );

  if (model.isUnavailable) return <p>Built-in AI is not available here.</p>;
  if (model.availability === "downloadable") {
    return (
      <button onClick={() => model.download()}>Enable on-device AI</button>
    );
  }
  if (model.isDownloading) return <progress value={model.progress} max={1} />;

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        void send();
      }}
    >
      {messages.map((message, index) => (
        <p key={index}>
          <b>{message.role}:</b> {message.content}
        </p>
      ))}
      <input value={input} onChange={(event) => setInput(event.target.value)} />
      <button disabled={isStreaming}>Send</button>
      {isStreaming && <button onClick={stop}>Stop</button>}
    </form>
  );
}

Using the other APIs

The React bindings follow the same shape across the task APIs: call the hook, read model, run the task, and render result or error. The names map directly to Chrome's APIs, which keeps the wrapper boring in a good way.

ai-tools.tsx
import {
  useLanguageDetector,
  usePrompt,
  useProofreader,
  useRewriter,
  useSummarizer,
  useTranslator,
  useWriter,
} from "@use-chrome-ai/react";

function AiTools({ article, draft }: { article: string; draft: string }) {
  const promptApi = usePrompt();
  const summarizer = useSummarizer({ type: "key-points", length: "short" });
  const writer = useWriter({ tone: "formal", length: "short" });
  const rewriter = useRewriter({ tone: "more-casual" });
  const proofreader = useProofreader();
  const translator = useTranslator({
    sourceLanguage: "en",
    targetLanguage: "es",
  });
  const detector = useLanguageDetector();

  async function runExamples() {
    await promptApi.prompt("Give me one label for this page.");
    await summarizer.summarize(article);
    await writer.write("Ask a customer for a missing invoice number.");
    await rewriter.rewrite(draft);
    await proofreader.proofread("I seen the bug yesturday.");
    await translator.translate("Good morning");
    await detector.detect("bonjour le monde");
  }

  return <button onClick={runExamples}>Run AI helpers</button>;
}

Vue and core

The Vue adapter has useChat and useModelStatus, and it re-exports the core controllers. That means Vue can use the same lower-level createSummarizer, createWriter, createRewriter, createTranslator, createProofreader, and createLanguageDetector APIs without waiting for a dedicated composable per feature.

summary.vue.ts
import { createSummarizer, useModelStatus } from "@use-chrome-ai/vue";

const summarizer = createSummarizer({ type: "key-points", length: "short" });
const status = useModelStatus(summarizer);

async function summarize(article: string) {
  if (status.value.availability === "downloadable") {
    await summarizer.download();
  }

  return summarizer.run({ text: article });
}