Membangun frontend untuk era AI: UI yang digenerate AI, streaming responses dengan SSE, agentic UX, dan pola UI untuk aplikasi LLM — dipraktikkan dengan asisten rekomendasi produk TokoKita

Episode 24 membawa kita ke garis depan: AI-native frontend. Berbeda dari "menambahkan chatbot ke aplikasi", AI-native berarti AI menjadi bagian dari fondasi pengalaman — UI yang beradaptasi, konten yang dihasilkan per pengguna, dan interaksi yang menyerupai percakapan dengan entitas yang berpikir.
Di 2026, kemampuan ini membedakan produk. Pemilik TokoKita tidak perlu lagi menyusun filter manual yang rumit — ia cukup bertanya "produk apa yang cocok untuk hadiah ulang tahun?" dan mendapatkan jawaban + antarmuka yang dibangun sesuai konteks. Frontend developer yang paham pola ini adalah aset langka.
| AI sebagai Fitur | AI-Native | |
|---|---|---|
| Posisi | Tombol/panel "AI" tambahan | AI tertanam di seluruh alur |
| Input | Form statis | Prompt, konteks, intent |
| Output | Hasil tetap yang dihitung | Konten/UI yang dihasilkan dinamis |
| Iterasi | User klik & menunggu | Percakapan multi-langkah |
| Contoh | Chatbot FAQ | Copilot yang membangun UI sesuai permintaan |
Pergeseran kuncinya: UI tidak lagi sepenuhnya ditentukan saat build — sebagian besar di-orkestrasi saat runtime berdasarkan konteks.
Generative UI — komponen yang dihasilkan model berdasarkan permintaan, dirender sebagai komponen React nyata (bukan sekadar teks HTML). Pola yang umum:
Sisi engineering yang paling penting: jangan render output model mentah (risiko XSS — episode 18). Validasi dengan skema (Zod), render lewat komponen yang sudah ada, dan hanya izinkan "building blocks" yang diizinkan sistem.
Model AI berpikir dan mengetik "per kata" — menunggu jawaban lengkap membuat pengguna menunggu belasan detik tanpa umpan balik. Solusinya streaming:
export async function POST(req: Request) {
const { prompt } = await req.json();
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
for await (const chunk of streamCompletion(prompt)) {
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
}
controller.close();
},
});
return new Response(stream, {
headers: {
"content-type": "text/event-stream",
"cache-control": "no-cache",
connection: "keep-alive",
},
});
}Di klien, gunakan API modern:
async function streamChat(prompt: string, onToken: (text: string) => void) {
const res = await fetch("/api/chat", {
method: "POST",
body: JSON.stringify({ prompt }),
});
const reader = res.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
onToken(decoder.decode(value, { stream: true }));
}
}Important
Streaming bukan fitur mewah — ia pola UX inti AI-native. Prinsip dari episode 5 (jangan blokir main thread) dan episode 12 (INP) berlaku penuh: render token yang masuk dengan ringan, jangan re-render seluruh halaman setiap token.
Agentic UX — antarmuka di mana AI bertindak (bukan sekadar menjawab): menjalankan aksi, mengumpulkan informasi, melaporkan kembali. Pola UX yang harus kalian kuasai:
sedang memeriksa stok → sedang menyiapkan pesanan).Pola ini adalah aksesibilitas versi AI: pengguna harus bisa mengikuti, menginterupsi, dan mengendalikan.
Fitur minimal AI-native untuk TokoKita:
export function ChatWidget() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
async function send() {
const userMsg = { role: "user", content: input };
setMessages((m) => [...m, userMsg]);
setInput("");
let acc = "";
setMessages((m) => [...m, { role: "assistant", content: "" }]);
await streamChat(input, (token) => {
acc += token;
setMessages((m) => {
const next = [...m];
next[next.length - 1] = { role: "assistant", content: acc };
return next;
});
});
}
return (
<div className="chat">
{messages.map((m, i) => (
<Message key={i} message={m} />
))}
<form onSubmit={(e) => { e.preventDefault(); send(); }}>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button type="submit">Kirim</button>
</form>
</div>
);
}Perhatikan: UI tetap harus bisa dioperasikan keyboard dan accessible (episode 15) — chat yang tidak accessible adalah fitur yang tersembunyi bagi sebagian pengguna.
| Kesalahan | Dampak | Perbaikan |
|---|---|---|
| Render output model mentah | XSS | Validasi skema + whitelist komponen |
| Menunggu jawaban penuh | UX buruk | Streaming SSE |
| Agent aksi tanpa konfirmasi | Pengguna kehilangan kontrol | Confirmation + undo |
| Re-render penuh tiap token | Jank & input hilang | Update targeted |
| Chat tanpa a11y | Sebagian pengguna terkunci | Keyboard + live regions |
Inti yang harus dibawa pulang:
Di episode 25 selanjutnya kita mengonsolidasi kerja tim: design systems & component libraries — tokens, Storybook, dan workflow desain-developer yang membuat TokoKita tumbuh konsisten dan efisien. Sampai jumpa di episode 25!