
Json Render
Install this when you are building or fixing a custom AI chat UI in Next.js/React and need correct UIMessage parts, tool-call displays, and streaming states instead of brittle markdown hacks.
Install
npx skills add https://github.com/vercel-labs/vercel-plugin --skill json-renderWhat is this skill?
- Guides rendering of AI SDK UIMessage parts, tool-call UI, and in-flight streaming states in custom chat shells
- Maps troubleshooting to structured data presentation rather than dumping raw model strings
- Auto-chains to ai-sdk when deprecated v5 patterns (message.content, tool-invocation) appear in the codebase
- Auto-chains to ai-elements when react-markdown, ReactMarkdown, or dangerouslySetInnerHTML is used for AI content
- Retrieval hooks for intents like render chat messages, display tool calls, and show streaming response
Adoption & trust: 55 installs on skills.sh; 187 GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Journey fit
The skill targets chat and message component paths and AI response display work that happens while you are actively building the product UI, not distribution or ops. Path patterns center on components/chat and message*.tsx files, which is frontend implementation of the agent conversation surface.
Common Questions / FAQ
Is Json Render safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Json Render
# AI Chat Response Rendering You are an expert in rendering AI SDK v6 chat responses — UIMessage parts, tool call results, streaming states, and structured data display in React applications. ## The Problem When building chat interfaces with AI SDK v6, the raw message format includes multiple part types (text, tool calls, reasoning, images). Without proper rendering, responses appear as raw JSON or malformed output. ## AI SDK v6 Message Format In v6, messages use the `UIMessage` type with a `parts` array: ```ts interface UIMessage { id: string role: 'user' | 'assistant' parts: UIMessagePart[] } // Part types: // - { type: 'text', text: string } // - { type: 'tool-<toolName>', toolCallId: string, state: string, input?: unknown, output?: unknown } // state values: 'partial-call' | 'call' | 'output-available' | 'approval-requested' | 'approval-responded' | 'output-denied' // - { type: 'reasoning', text: string } // - { type: 'step-start' } // internal, skip in rendering ``` ## Recommended: Use AI Elements The simplest approach is to use AI Elements, which handles all part types automatically: ```tsx import { Message } from '@/components/ai-elements/message' import { Conversation } from '@/components/ai-elements/conversation' {messages.map((message) => ( <Message key={message.id} message={message} /> ))} ``` ⤳ skill: ai-elements — Full component library for AI interfaces ## Manual Rendering Pattern If you need custom rendering without AI Elements, follow this pattern: ```tsx 'use client' import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' export function Chat() { const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: '/api/chat' }), }) const isLoading = status === 'streaming' || status === 'submitted' return ( <div> {messages.map((message) => ( <div key={message.id}> {message.parts?.map((part, i) => { // 1. Text parts — render as formatted text if (part.type === 'text' && part.text.trim()) { return ( <div key={i} className={ message.role === 'user' ? 'bg-primary text-primary-foreground rounded-lg px-3 py-2' : 'bg-muted rounded-lg px-3 py-2' }> {part.text} </div> ) } // 2. Tool parts — type is "tool-<toolName>" if (pa