UI2 Docs
React Quick Start

Quick Start Overview

What are we building?

If you haven't already, it can be helpful to read the Core Quick Start, but this course will also make sense without it.

In this Quick Start guide, we'll be creating our first UI2 application, with Next.js and React.

We'll be using a custom React UI2 hook that's powered by a Stateful UI2 API, allowing you to easily combine UI2 with your existing apps, or to build a completely new app with UI2.

We will add multiple intents, explore UI2's powerful React integration, and also learn how to use UI2 to identify and submit intents based on a textbox content.

The Result

The final code is also available on GitHub in the /examples folder. Check it out here.

You'll create a simple Todo app that has two main features:

  • Adding a Todo: Create a new todo with a name
  • Complete Todo: Helps you mark a todo as done

You'll be able to use these features by simply typing into a UI2 Input, and you'll be able to see live previews of the intents as they are being identified.

You'll be seeing how we can use UI2's features including:

  • Context: A simple way to provide UI2 with context about your app
  • Intent ID: A way to keep track of what intents are being called—and reduce unnecessary re-renders
  • Cleanup: An event listener called when an intent is no longer detected

This is the final code we will be writing:

"use client";
import { useUI2 } from "ui2-sdk/react";
import { createCerebras } from "@ai-sdk/cerebras";
import { useState } from "react";
import { z } from "zod";
 
export default function Page() {
	const [todos, setTodos] = useState<
		{
			id: string;
			name: string;
			completed: boolean;
			preview: boolean;
		}[]
	>([]);
 
	let cerebras = createCerebras({
		apiKey: "API_KEY",
	});
 
	let { inputValue, handleInputChange, handleSubmit } = useUI2({
		model: cerebras("llama-3.3-70b"),
		systemPrompt: "This is a todo app.",
		context: todos.filter((x) => !x.preview),
	})
		.addIntent("addTodo", {
			description: "Add a todo",
			parameters: z.object({
				name: z.string(),
			}),
			onIntent: ({ parameters, id }) => {
				setTodos((prev) => [
					...prev,
					{
						id,
						name: parameters.name,
						completed: false,
						preview: true,
					},
				]);
			},
			onCleanup: ({ parameters, id }) => {
				setTodos((prev) => prev.filter((x) => x.id !== id));
			},
			onSubmit: ({ id }) =>
				setTodos((prev) =>
					prev.map((x) => (x.id === id ? { ...x, preview: false } : x))
				),
		})
		.addIntent("completeTodo", {
			description: "complete a todo",
			parameters: z.object({
				id: z.string(),
			}),
			onIntent: ({ parameters }) => {
				setTodos((prev) =>
					prev.map((x) =>
						x.id === parameters.id
							? { ...x, preview: true, completed: true }
							: x
					)
				);
			},
			onCleanup: ({ parameters }) => {
				setTodos((prev) =>
					prev.map((x) =>
						x.id === parameters.id
							? { ...x, preview: false, completed: false }
							: x
					)
				);
			},
			onSubmit: ({ parameters }) =>
				setTodos((prev) =>
					prev.map((x) =>
						x.id === parameters.id
							? { ...x, preview: false, completed: true }
							: x
					)
				),
		});
 
	return (
		<div className="w-screen h-screen flex flex-col items-center justify-between p-4">
			{todos.length
				? todos.map((x) => (
						<div key={x.id} className={x.preview ? "opacity-50" : ""}>
							{x.name} - {x.completed ? "Completed" : "Todo"}
						</div>
				  ))
				: "No todos"}
			<div className="flex flex-row gap-2">
				<input
					className="p-1 outline"
					value={inputValue}
					onChange={(e) => handleInputChange(e.target.value)}
				/>
				<button className="p-1 outline" onClick={handleSubmit}>
					Submit
				</button>
			</div>
		</div>
	);
}

It might look complicated, but working with UI2 is as simple as describing your Intent in code.

If you're ready to identify some intents with your React app, let's get right into it!

On this page