The useCompletion Hook
The useCompletion hook is designed for single-turn text completion scenarios,
such as autocomplete, text generation, and AI-powered writing assistance. Unlike useChat,
it doesn't maintain a conversation history.
Use Cases for useCompletion
- Autocomplete: Suggest completions as users type
- Text Generation: Generate content from a prompt
- Writing Assistant: Help users write emails, articles, etc.
- Code Completion: AI-powered code suggestions
- Summarization: Summarize text input
Basic Usage
'use client';
import { useCompletion } from 'ai/react';
export default function TextGenerator() {
const {
completion,
input,
handleInputChange,
handleSubmit,
isLoading,
} = useCompletion();
return (
<div className="max-w-xl mx-auto p-4">
<form onSubmit={handleSubmit}>
<textarea
value={input}
onChange={handleInputChange}
placeholder="Enter a prompt..."
className="w-full p-2 border rounded-lg"
rows={4}
/>
<button
type="submit"
disabled={isLoading}
className="mt-2 px-4 py-2 bg-purple-500 text-white rounded-lg"
>
{isLoading ? 'Generating...' : 'Generate'}
</button>
</form>
{completion && (
<div className="mt-4 p-4 bg-gray-100 rounded-lg">
<h3 className="font-semibold mb-2">Result:</h3>
<p className="whitespace-pre-wrap">{completion}</p>
</div>
)}
</div>
);
}
Server-Side API Route
// app/api/completion/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText } from 'ai';
export async function POST(req: Request) {
const { prompt } = await req.json();
const result = streamText({
model: openai('gpt-4-turbo'),
prompt,
});
return result.toDataStreamResponse();
}
All useCompletion Options
const {
completion, // The generated text
input, // Current input value
handleInputChange, // Input onChange handler
handleSubmit, // Form onSubmit handler
isLoading, // Loading state
error, // Error state
stop, // Stop generation
setCompletion, // Manually set completion
setInput, // Manually set input
complete, // Trigger completion programmatically
} = useCompletion({
api: '/api/completion', // API endpoint
id: 'my-completion', // Unique ID
// Callbacks
onResponse: (response) => {
console.log('Response started');
},
onFinish: (prompt, completion) => {
console.log('Completed:', completion);
},
onError: (error) => {
console.error('Error:', error);
},
// Additional options
headers: {},
body: {},
});
Autocomplete Example
'use client';
import { useCompletion } from 'ai/react';
import { useState, useEffect } from 'react';
export default function Autocomplete() {
const [debouncedInput, setDebouncedInput] = useState('');
const { completion, input, setInput, complete, isLoading } = useCompletion({
api: '/api/autocomplete',
});
// Debounce input
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedInput(input);
}, 500);
return () => clearTimeout(timer);
}, [input]);
// Trigger completion when debounced input changes
useEffect(() => {
if (debouncedInput.length > 10) {
complete(debouncedInput);
}
}, [debouncedInput, complete]);
const acceptSuggestion = () => {
setInput(input + completion);
};
return (
<div className="relative">
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
className="w-full p-4 border rounded-lg"
rows={6}
/>
{completion && !isLoading && (
<div className="absolute bottom-2 right-2">
<span className="text-gray-400 italic">{completion}</span>
<button
onClick={acceptSuggestion}
className="ml-2 text-sm text-blue-500"
>
Tab to accept
</button>
</div>
)}
</div>
);
}
Writing Assistant
'use client';
import { useCompletion } from 'ai/react';
export default function WritingAssistant() {
const { completion, complete, isLoading, setCompletion } = useCompletion({
api: '/api/writing-assist',
});
const actions = [
{ label: 'Make it shorter', prompt: 'Make this text more concise:' },
{ label: 'Make it longer', prompt: 'Expand on this text:' },
{ label: 'Fix grammar', prompt: 'Fix grammar and spelling:' },
{ label: 'Make it formal', prompt: 'Rewrite in a formal tone:' },
{ label: 'Make it casual', prompt: 'Rewrite in a casual tone:' },
];
const [text, setText] = useState('');
const handleAction = (promptPrefix: string) => {
complete(`${promptPrefix}\n\n${text}`);
};
const applyResult = () => {
setText(completion);
setCompletion('');
};
return (
<div className="space-y-4">
<textarea
value={text}
onChange={(e) => setText(e.target.value)}
className="w-full p-4 border rounded-lg"
rows={6}
placeholder="Enter your text..."
/>
<div className="flex flex-wrap gap-2">
{actions.map((action) => (
<button
key={action.label}
onClick={() => handleAction(action.prompt)}
disabled={isLoading || !text}
className="px-3 py-1 bg-gray-100 rounded-full text-sm"
>
{action.label}
</button>
))}
</div>
{completion && (
<div className="p-4 bg-purple-50 rounded-lg">
<p className="whitespace-pre-wrap">{completion}</p>
<button
onClick={applyResult}
className="mt-2 px-4 py-2 bg-purple-500 text-white rounded-lg"
>
Apply changes
</button>
</div>
)}
</div>
);
}
Programmatic Completion
'use client';
import { useCompletion } from 'ai/react';
export default function ProgrammaticCompletion() {
const { completion, complete, isLoading } = useCompletion();
const generateEmailSubject = async () => {
await complete('Generate a professional email subject line about:' +
' requesting a meeting with the marketing team');
};
const generateTweet = async () => {
await complete('Write a tweet about the benefits of TypeScript');
};
return (
<div className="space-y-4">
<div className="flex gap-2">
<button onClick={generateEmailSubject}>Email Subject</button>
<button onClick={generateTweet}>Generate Tweet</button>
</div>
{isLoading && <p>Generating...</p>}
{completion && (
<div className="p-4 bg-gray-100 rounded-lg">
{completion}
</div>
)}
</div>
);
}
useChat vs useCompletion
| Feature | useChat | useCompletion |
|---|---|---|
| Message History | Yes | No |
| Multi-turn | Yes | No |
| Use Case | Chatbots | Single completions |
| Output | messages[] | completion string |
Key Takeaways
- •
useCompletionis for single-turn text generation - • Perfect for autocomplete, writing tools, and one-off generations
- • Use
complete()for programmatic triggering - • Doesn't maintain conversation history like
useChat - • Combine with debouncing for real-time autocomplete
Learn More
-
useCompletion Documentation →
Complete API reference for the useCompletion hook.