Maximal Studio
Maximal Studio
ResourcesBlogTools
Back to all posts

Interactive JSX Previewer for AI Coding Platforms

When working with AI-generated code, especially in React applications, being able to instantly preview JSX output becomes crucial. The JSXPreview component solves this challenge by rendering JSX strings as React components in real-time, with support for streaming content and automatic tag completion.

The Problem with AI-Generated JSX

AI models often generate JSX code incrementally, which can lead to incomplete tags and broken rendering. Traditional approaches require waiting for the complete output before rendering, creating a disjointed experience for users.

Introducing JSX Preview

Our JSXPreview component solves these problems with two key features:

  1. Direct JSX Rendering: Convert JSX strings to live React components
  2. Tag Completion: Automatically complete open tags during streaming

JSX Input

Preview

Waiting for input

How It Works

The component works through a combination of JSX parsing and intelligent tag completion:

function JSXPreview({ jsx, isStreaming = false, ...props }: JSXPreviewProps) {
  const processedJsx = React.useMemo(
    () => (isStreaming ? completeJsxTag(jsx) : jsx),
    [jsx, isStreaming]
  )

  // Cast JsxParser to any to work around the type incompatibility
  const Parser = JsxParser as unknown as React.ComponentType<JsxParserProps>

  return <Parser jsx={processedJsx} {...props} />
}

When isStreaming is enabled, the component automatically balances opening and closing tags, allowing for real-time preview even with incomplete JSX input.

Tag Completion Logic

The core of our component lies in the completeJsxTag function:

function completeJsxTag(code: string) {
  const stack: string[] = []
  let result = ""
  let currentPosition = 0

  while (currentPosition < code.length) {
    const match = matchJsxTag(code.slice(currentPosition))
    if (!match) break
    const { tagName, type, endIndex } = match

    if (type === "opening") {
      stack.push(tagName)
    } else if (type === "closing") {
      stack.pop()
    }

    result += code.slice(currentPosition, currentPosition + endIndex)
    currentPosition += endIndex
  }

  return (
    result +
    stack
      .reverse()
      .map((tag) => `</${tag}>`)
      .join("")
  )
}

This function maintains a stack of open tags and automatically generates closing tags when needed, ensuring valid JSX even during streaming.

Usage Examples

Basic JSX Preview

import { JSXPreview } from "@/components/jsxPreview";

export default function Example() {
  return (
    <JSXPreview 
      jsx="<div><h1>Hello World</h1><p>This is a preview</p></div>" 
    />
  );
}

Streaming JSX Preview

import { JSXPreview } from "@/components/jsxPreview";
import { useState, useEffect } from "react";

export default function StreamingExample() {
  const [jsx, setJsx] = useState("");
  
  useEffect(() => {
    const fullJsx = "<div><h1>Hello World</h1><p>This is being streamed";
    let current = "";
    let index = 0;
    
    const interval = setInterval(() => {
      if (index < fullJsx.length) {
        current += fullJsx[index];
        setJsx(current);
        index++;
      } else {
        clearInterval(interval);
      }
    }, 100);
    
    return () => clearInterval(interval);
  }, []);
  
  return <JSXPreview jsx={jsx} isStreaming={true} />;
}

Use Cases

AI Code Generation

The JSXPreview component is particularly useful when integrated with AI code generation tools:

  • Real-time preview of AI-generated components
  • Visual feedback during iterative code generation
  • Interactive prototyping with AI assistance

Credits

This component was inspired by the work done at Prompt Kit, which offers various tools for working with AI-generated content.