Skip to content

About

Nuxt/Vue complement to Vercel AI Elements — headless AI UI for the AI SDK (chat, agents, tools, workflow).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ai-elements-nuxt

CI license version

Nuxt/Vue complement to Vercel AI Elements — headless AI UI components for the AI SDK ecosystem.

Documentation · npm · Contributing · Code of Conduct · Security · Changelog

Not a replacement for AI Elements. This project extends the same UI patterns to Nuxt 3 and Vue 3 so you can build AI-native apps with your own design system.

Install

1. Core (always required):

pnpm add ai-elements-nuxt ai @ai-sdk/vue

2. Choose a model provider (at least one required for production):

pnpm add @ai-sdk/openai        # OpenAI / GPT-4o
# pnpm add @ai-sdk/anthropic   # Anthropic / Claude
# pnpm add @ai-sdk/google      # Google / Gemini
# pnpm add @ai-sdk/mistral     # Mistral

Full provider list → ai-sdk.dev/providers

3. Agents only — add Zod for tool parameter schemas:

pnpm add zod

Set your API key in .env (Nuxt reads it automatically):

OPENAI_API_KEY=sk-...

Register the module:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['ai-elements-nuxt'],
  aiElements: {
    defaultStyles: true, // optional base CSS for [data-ai-*] attributes
  },
})

What do you need?

Goal Key components Composable Server handler
Streaming chat AiMessage, AiPromptInput useAiChat createChatHandler
Agent with tools + AiAgent, AiTool, AiToolApproval useAiAgent, useAiTools createAgentHandler
Persisted chat same as chat useAiChatPersisted same as chat
Realtime voice AiRealtimeChat useAiRealtime —

Install from GitHub

To use the latest commit from the repository instead of the npm release:

pnpm add github:albegosu/ai-elements-nuxt

With pnpm strict build settings, allow the module to run its prepack build:

# pnpm-workspace.yaml (consumer monorepo root)
allowBuilds:
  ai-elements-nuxt: true

Types in consumer apps:

import type { AiMessageProps, AiSource } from 'ai-elements-nuxt/types'

Quick start (streaming chat)

1. Server route (server/api/chat.post.ts):

// Start with mock (no API key needed):
import { createMockChatHandler } from 'ai-elements-nuxt/server'
export default createMockChatHandler()

// Swap for production:
// import { createChatHandler } from 'ai-elements-nuxt/server'
// import { openai } from '@ai-sdk/openai'
// export default createChatHandler({ model: openai('gpt-4o') })

2. Page:

<script setup lang="ts">
const { aiMessages, input, handleSubmit, isStreaming } = useAiChat({ api: '/api/chat' })
</script>

<template>
  <AiMessage v-for="(msg, i) in aiMessages" :key="i" v-bind="msg">
    <template #content="{ content, isStreaming: streaming }">
      <AiStreamingCursor v-if="streaming && content" :active="true" />
      {{ content }}
    </template>
  </AiMessage>
  <form @submit="handleSubmit">
    <AiPromptInput v-model="input" :loading="isStreaming" />
  </form>
</template>

Agentic apps

Server — multi-step tools with optional human approval:

import { createAgentHandler } from 'ai-elements-nuxt/server'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'

export default createAgentHandler({
  model: openai('gpt-4o'),
  maxSteps: 10,
  tools: {
    getWeather: {
      description: 'Get weather for a city',
      parameters: z.object({ city: z.string() }),
      execute: async ({ city }) => ({ temp: 72, city }),
    },
    deleteFile: {
      description: 'Delete a file',
      parameters: z.object({ path: z.string() }),
      requireConfirmation: true,
      execute: async ({ path }) => ({ deleted: path }),
    },
  },
})

Client — useAiAgent + useAiTools:

<script setup lang="ts">
const agent = useAiAgent({ api: '/api/chat' })
// useAiTools wires per-tool metadata; pendingApprovals is already AiToolCall[] — no reshaping needed
const tools = useAiTools([
  { name: 'getWeather' },
  { name: 'deleteFile', requireConfirmation: true },
], agent)
const { aiMessages, steps, handleSubmit, input } = agent
</script>

<template>
  <!-- AiAgent (also AiAgentSteps) renders the steps[] from useAiAgent -->
  <AiAgent :steps="steps" title="Agent run" />

  <!-- pendingApprovals[0] is already AiToolCall-shaped — pass directly -->
  <AiToolApproval
    v-if="tools.pendingApprovals.value[0]"
    :tool-call="tools.pendingApprovals.value[0]"
    @approve="tools.approveTool"
    @deny="tools.denyTool"
  />

  <AiMessage v-for="(msg, i) in aiMessages" :key="i" v-bind="msg" />
  <form @submit="handleSubmit">
    <AiPromptInput v-model="input" />
  </form>
</template>

See AGENTS.md for step-by-step recipes for coding agents.

Markdown rendering

<script setup lang="ts">
const { html } = useAiMarkdown(() => markdownSource)
</script>

<template>
  <AiMarkdown :content="markdownSource" />
  <!-- or -->
  <div v-html="html" />
</template>

GFM (tables, task lists, strikethrough) is enabled by default via marked. Use auto-imported simpleParse for a lightweight fallback (no tables — useful during streaming to avoid layout shifts):

const { html } = useAiMarkdown(() => markdownSource, { parse: simpleParse })

Components (66)

All components are auto-imported with the Ai prefix.

Category Components
Chatbot Message, PromptInput, Conversation (thread list / sidebar), Reasoning, ChainOfThought, Sources, Tool, ToolApproval, ApprovalPolicy, Suggestion, Attachments, Shimmer, StreamingCursor, Plan, Task, Checkpoint, Confirmation, Context, Queue, InlineCitation, ModelSelector, ErrorBoundary, ScreenshotButton, DownloadConversation, Branch, SpeechButton, SourceDocuments
Code CodeBlock, Terminal, FileTree, StackTrace, Agent (also AiAgentSteps), AgentTimeline, Artifact, Commit, SchemaDisplay, PackageInfo, EnvVars, TestResults, Snippet, WebPreview, Sandbox, SandboxPreview, VuePreview
Voice SpeechInput, Transcription, AudioPlayer, MicSelector, VoiceSelector, Persona, RealtimeChat
Workflow Canvas, Node, Edge, Connection, Controls, Panel, Toolbar
Utilities Image, OpenInChat, Markdown, JsxPreview, FileUpload, VideoPlayer, McpApp, RuntimeContext

Composables

Composable Description
useAiChat Wraps @ai-sdk/vue Chat when api is set; supports body / headers / credentials; local state without api
useAiChatLocal Local message state without AI SDK
useAiChatPersisted useAiChat with localStorage/sessionStorage persistence
useAiAgent Agent steps, plan, tasks, and confirmation flow on top of chat
useAiTools Declarative per-tool UI metadata wired to useAiAgent; exposes pendingApprovals (typed AiToolCall[]) for AiToolApproval
useAiRealtime Vue composable wrapping AI SDK v7 AbstractRealtimeSession — connection, audio capture/playback, messages
useAiWorkflow Workflow graph nodes/edges state
useAiCompletion Wraps @ai-sdk/vue useCompletion
useAiMarkdown Markdown string → sanitized HTML (GFM via marked); pass { parse: simpleParse } for lightweight fallback
useScreenshotCapture Capture a screenshot via getDisplayMedia → { dataUrl, blob, file } for prompt attachments
useSpeechRecognition Web Speech API wrapper (start/stop/toggle, transcript, interim, supported) — powers AiSpeechInput / AiSpeechButton
mapMessageParts / toAiMessageProps Map AI SDK UIMessage.parts → AiMessage props

Server utilities

import {
  createChatHandler,
  createMockChatHandler,
  createAgentHandler,
} from 'ai-elements-nuxt/server'

For AI agents (MCP + skill)

The package ships tooling so coding agents can build with the library accurately:

  • MCP server — a Model Context Protocol stdio server exposing the component registry:

    npx ai-elements-nuxt-mcp

    Tools: list_components, get_component, search_components, list_composables; resource ai-elements://registry. Add it to your MCP client (Claude Code / Cursor) as a stdio server running that command.

  • Skill — skills/ai-elements-nuxt/SKILL.md, an installable agent skill with an auto-generated component list. Copy it into your agent's skills directory (e.g. .claude/skills/).

  • Registry JSON — import the raw metadata directly: import registry from 'ai-elements-nuxt/registry'.

  • AGENTS.md — full implementation guide (also drives .cursor/rules).

The component/composable lists in the skill and AGENTS.md are generated from registry/components.json, so they never drift from the code.

Development

git clone https://github.com/albegosu/ai-elements-nuxt.git
cd ai-elements-nuxt
pnpm install
pnpm dev

See .github/CONTRIBUTING.md for the full contributor guide (lint, test, docs conventions).

Documentation & playground

pnpm dev

Opens the docs site at http://localhost:3000 (or the hosted docs) with:

  • Guides: getting started, building a chat, custom transport & RAG, building an agent, styling, composables
  • Component reference with Preview/Code tabs for all 66 components
  • Playgrounds: chat, streaming, agent, code, voice & workflow

Philosophy

  • Headless: slot-driven, data-ai-* attributes, no forced design system
  • Compatible: follows AI SDK UIMessage.parts contract
  • Nuxt-native: module auto-imports, Nitro server helpers
  • Agent-ready: AGENTS.md and .cursor/rules/ for AI coding tools

Credits

Inspired by and designed to complement vercel/ai-elements and the AI SDK.

Contributing

Contributions are welcome. Please read CONTRIBUTING.md and our Code of Conduct before opening a pull request.

License

MIT

About

Nuxt/Vue complement to Vercel AI Elements — headless AI UI for the AI SDK (chat, agents, tools, workflow).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages