Execute React components on the fly with external dependencies, custom styling, and TypeScript support. Perfect for creating live code previews, documentation, or interactive code playgrounds.

Try the live demo here.
- 🚀 Execute React components from string code
- 📦 Support for external dependencies
- 🎨 Tailwind CSS support
- 🔒 Built-in security checks
- 💅 Customizable styling
- 📝 TypeScript support
- ⚡ Live rendering
- 🐛 Error boundary protection
- 📄 Multi-file support
npm install react-exe
# or
yarn add react-exe
# or
pnpm add react-exe
import { CodeExecutor } from "react-exe";
const code = `
export default function HelloWorld() {
return (
<div className="p-4 bg-blue-100 rounded">
<h1 className="text-2xl font-bold">Hello World!</h1>
</div>
);
}
`;
function App() {
return <CodeExecutor code={code} config={{ enableTailwind: true }} />;
}
import { CodeExecutor } from "react-exe";
import * as echarts from "echarts";
import * as framerMotion from "framer-motion";
const code = `
import { motion } from 'framer-motion';
import { LineChart } from 'echarts';
export default function Dashboard() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="p-6 space-y-4"
>
<LineChart
option={{
xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
yAxis: { type: 'value' },
series: [{ data: [150, 230, 224], type: 'line' }]
}}
style={{ height: '300px' }}
/>
</motion.div>
);
}
`;
function App() {
return (
<CodeExecutor
code={code}
config={{
dependencies: {
"framer-motion": framerMotion,
echarts: echarts,
},
enableTailwind: true,
containerClassName: "min-h-[400px]",
containerStyle: {
padding: "20px",
background: "#f9fafb",
},
}}
/>
);
}
import { CodeExecutor } from "react-exe";
import * as echarts from "echarts";
import * as framerMotion from "framer-motion";
import * as uiComponents from "../ShadcnComps";
const code = `
import { motion } from 'framer-motion';
import { LineChart } from 'echarts';
import { Button } from "@/components/ui/button"
export default function Dashboard() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="p-6 space-y-4"
>
<LineChart
option={{
xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed'] },
yAxis: { type: 'value' },
series: [{ data: [150, 230, 224], type: 'line' }]
}}
style={{ height: '300px' }}
/>
</motion.div>
);
}
`;
function App() {
return (
<CodeExecutor
code={code}
config={{
dependencies: {
"framer-motion": framerMotion,
echarts: echarts,
"@/components/ui/*": uiComponents,
},
enableTailwind: true,
containerClassName: "min-h-[400px]",
containerStyle: {
padding: "20px",
background: "#f9fafb",
},
}}
/>
);
}
React-EXE supports multiple files with cross-imports, allowing you to build more complex components and applications:
import { CodeExecutor } from "react-exe";
import * as framerMotion from "framer-motion";
// Define multiple files as an array of code files
const files = [
{
name: "App.tsx", // Main entry file
content: `
import React from 'react';
import { motion } from 'framer-motion';
import Header from './Header';
import Counter from './Counter';
const App = () => {
return (
<motion.div
className="min-h-screen bg-gray-100 p-4"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
<Header title="Multi-File App Example" />
<Counter />
</motion.div>
);
};
export default App;
`,
isEntry: true, // Mark this as the entry point
},
{
name: "Header.tsx",
content: `
import React from 'react';
interface HeaderProps {
title: string;
}
const Header = ({ title }: HeaderProps) => {
return (
<header className="bg-white p-4 mb-4 rounded-lg shadow-md">
<h1 className="text-2xl font-bold text-gray-800">{title}</h1>
</header>
);
};
export default Header;
`,
},
{
name: "Counter.tsx",
content: `
import React, { useState } from 'react';
import { motion } from 'framer-motion';
import CounterButton from './CounterButton';
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => setCount(prev => prev + 1);
const decrement = () => setCount(prev => prev - 1);
return (
<div className="bg-white p-6 rounded-lg shadow-md">
<h2 className="text-xl font-semibold mb-4">Counter Component</h2>
<motion.div
className="text-center text-3xl font-bold my-4"
key={count}
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
>
{count}
</motion.div>
<div className="flex justify-center gap-4">
<CounterButton onClick={decrement} label="Decrease" variant="danger" />
<CounterButton onClick={increment} label="Increase" variant="success" />
</div>
</div>
);
};
export default Counter;
`,
},
{
name: "CounterButton.tsx",
content: `
import React from 'react';
import { motion } from 'framer-motion';
interface CounterButtonProps {
onClick: () => void;
label: string;
variant?: 'primary' | 'success' | 'danger';
}
const CounterButton = ({
onClick,
label,
variant = 'primary'
}: CounterButtonProps) => {
const getButtonColor = () => {
switch(variant) {
case 'success': return 'bg-green-500 hover:bg-green-600';
case 'danger': return 'bg-red-500 hover:bg-red-600';
default: return 'bg-blue-500 hover:bg-blue-600';
}
};
return (
<motion.button
className={\`\${getButtonColor()} text-white py-2 px-4 rounded\`}
onClick={onClick}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
{label}
</motion.button>
);
};
export default CounterButton;
`,
},
];
function App() {
return (
<CodeExecutor
code={files}
config={{
dependencies: {
"framer-motion": framerMotion,
},
enableTailwind: true,
containerClassName: "rounded-lg overflow-hidden",
}}
/>
);
}
For more complex applications, you can organize your files in a project-like structure:
import { CodeExecutor } from "react-exe";
import * as reactRouter from "react-router-dom";
import * as framerMotion from "framer-motion";
const files = [
{
name: "App.tsx",
content: `
import React from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Layout from './components/Layout';
import Home from './pages/Home';
import About from './pages/About';
import NotFound from './pages/NotFound';
const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
);
};
export default App;
`,
isEntry: true,
},
{
name: "components/Layout.tsx",
content: `
import React from 'react';
import { Outlet } from 'react-router-dom';
import Navbar from './Navbar';
import Footer from './Footer';
const Layout = () => {
return (
<div className="min-h-screen flex flex-col">
<Navbar />
<main className="flex-grow container mx-auto px-4 py-8">
<Outlet />
</main>
<Footer />
</div>
);
};
export default Layout;
`,
},
{
name: "components/Navbar.tsx",
content: `
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
const Navbar = () => {
const location = useLocation();
const isActive = (path: string) => {
return location.pathname === path ?
'text-white bg-indigo-700' :
'text-indigo-200 hover:text-white hover:bg-indigo-600';
};
return (
<nav className="bg-indigo-800 text-white shadow-md">
<div className="container mx-auto px-4">
<div className="flex justify-between items-center h-16">
<Link to="/" className="font-bold text-xl">Multi-File App</Link>
<div className="flex space-x-4">
<Link
to="/"
className={\`px-3 py-2 rounded-md \${isActive('/')}\`}
>
Home
</Link>
<Link
to="/about"
className={\`px-3 py-2 rounded-md \${isActive('/about')}\`}
>
About
</Link>
</div>
</div>
</div>
</nav>
);
};
export default Navbar;
`,
},
{
name: "components/Footer.tsx",
content: `
import React from 'react';
const Footer = () => {
return (
<footer className="bg-gray-800 text-white py-6">
<div className="container mx-auto px-4 text-center">
<p>© {new Date().getFullYear()} React-EXE Demo</p>
<p className="text-gray-400 text-sm mt-1">Built with multiple files</p>
</div>
</footer>
);
};
export default Footer;
`,
},
{
name: "pages/Home.tsx",
content: `
import React from 'react';
import { motion } from 'framer-motion';
const Home = () => {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<h1 className="text-3xl font-bold mb-6">Welcome to the Home Page</h1>
<p className="mb-4">This is a multi-file application example using React-EXE.</p>
<p className="mb-4">
It demonstrates how you can create complex applications with multiple
components, pages, and even routing!
</p>
<div className="mt-8 p-6 bg-indigo-50 rounded-lg shadow-sm">
<h2 className="text-xl font-semibold mb-4">Features Demonstrated:</h2>
<ul className="list-disc pl-5 space-y-2">
<li>Multiple file structure</li>
<li>React Router integration</li>
<li>Animation with Framer Motion</li>
<li>Component composition</li>
<li>Styling with Tailwind CSS</li>
</ul>
</div>
</motion.div>
);
};
export default Home;
`,
},
{
name: "pages/About.tsx",
content: `
import React from 'react';
import { motion } from 'framer-motion';
const About = () => {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<h1 className="text-3xl font-bold mb-6">About Page</h1>
<p className="mb-4">
React-EXE is a powerful library for executing React components on the fly.
It supports multi-file applications like this one!
</p>
<motion.div
className="mt-8 grid grid-cols-1 md:grid-cols-3 gap-4"
variants={{
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: {
staggerChildren: 0.2
}
}
}}
initial="hidden"
animate="show"
>
{[1, 2, 3].map((item) => (
<motion.div
key={item}
className="bg-white p-6 rounded-lg shadow-md"
variants={{
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 }
}}
>
<h3 className="font-bold text-lg mb-2">Feature {item}</h3>
<p className="text-gray-600">
This is an example of a card that demonstrates Framer Motion animations
in a multi-file React component.
</p>
</motion.div>
))}
</motion.div>
</motion.div>
);
};
export default About;
`,
},
{
name: "pages/NotFound.tsx",
content: `
import React from 'react';
import { Link } from 'react-router-dom';
import { motion } from 'framer-motion';
const NotFound = () => {
return (
<motion.div
className="text-center py-12"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
>
<motion.div
initial={{ scale: 0.8 }}
animate={{ scale: 1 }}
transition={{
type: "spring",
stiffness: 200,
damping: 10
}}
>
<h1 className="text-9xl font-bold text-indigo-200">404</h1>
</motion.div>
<h2 className="text-3xl font-bold mb-4">Page Not Found</h2>
<p className="text-gray-600 mb-8">
The page you're looking for doesn't exist or has been moved.
</p>
<Link
to="/"
className="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition-colors"
>
Return Home
</Link>
</motion.div>
);
};
export default NotFound;
`,
},
];
function App() {
return (
<CodeExecutor
code={files}
config={{
dependencies: {
"react-router-dom": reactRouter,
"framer-motion": framerMotion,
},
enableTailwind: true,
}}
/>
);
}
You can also create and use custom hooks, utilities, and TypeScript types across multiple files:
import { CodeExecutor } from "react-exe";
const files = [
{
name: "App.tsx",
content: `
import React from 'react';
import ThemeProvider from './theme/ThemeProvider';
import ThemeSwitcher from './components/ThemeSwitcher';
import UserProfile from './components/UserProfile';
import { fetchUserData } from './utils/api';
const App = () => {
return (
<ThemeProvider>
<div className="min-h-screen p-6">
<div className="max-w-lg mx-auto">
<div className="flex justify-end mb-6">
<ThemeSwitcher />
</div>
<UserProfile userId="1" fetchUserData={fetchUserData} />
</div>
</div>
</ThemeProvider>
);
};
export default App;
`,
isEntry: true,
},
{
name: "types/index.ts",
content: `
export interface User {
id: string;
name: string;
email: string;
avatar: string;
}
export type Theme = 'light' | 'dark' | 'system';
export interface ThemeContextType {
theme: Theme;
setTheme: (theme: Theme) => void;
}
`,
},
{
name: "theme/ThemeProvider.tsx",
content: `
import React, { createContext, useContext, useState, useEffect } from 'react';
import { Theme, ThemeContextType } from '../types';
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [theme, setTheme] = useState<Theme>('system');
useEffect(() => {
const applyTheme = (newTheme: Theme) => {
const root = window.document.documentElement;
// Remove any existing theme classes
root.classList.remove('light', 'dark');
// Apply the appropriate theme
if (newTheme === 'system') {
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
root.classList.add(systemTheme);
} else {
root.classList.add(newTheme);
}
};
applyTheme(theme);
// Listen for system theme changes
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleChange = () => {
if (theme === 'system') {
applyTheme('system');
}
};
mediaQuery.addEventListener('change', handleChange);
return () => mediaQuery.removeEventListener('change', handleChange);
}, [theme]);
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
};
export default ThemeProvider;
`,
},
{
name: "components/ThemeSwitcher.tsx",
content: `
import React from 'react';
import { useTheme } from '../theme/ThemeProvider';
import { Theme } from '../types';
const ThemeSwitcher = () => {
const { theme, setTheme } = useTheme();
const themes: { value: Theme; label: string }[] = [
{ value: 'light', label: '☀️ Light' },
{ value: 'dark', label: '🌙 Dark' },
{ value: 'system', label: '🖥️ System' }
];
return (
<div className="bg-white dark:bg-gray-800 p-3 rounded-lg shadow-md inline-block">
<div className="flex space-x-2">
{themes.map(({ value, label }) => (
<button
key={value}
onClick={() => setTheme(value)}
className={\`px-3 py-1 rounded-md \${
theme === value
? 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-200'
: 'hover:bg-gray-100 dark:hover:bg-gray-700'
}\`}
>
{label}
</button>
))}
</div>
</div>
);
};
export default ThemeSwitcher;
`,
},
{
name: "hooks/useUser.ts",
content: `
import { useState, useEffect } from 'react';
import { User } from '../types';
export const useUser = (
userId: string,
fetchUserData: (id: string) => Promise<User>
) => {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
let isMounted = true;
const loadUser = async () => {
try {
setLoading(true);
const userData = await fetchUserData(userId);
if (isMounted) {
setUser(userData);
setError(null);
}
} catch (err) {
if (isMounted) {
setError('Failed to load user');
setUser(null);
}
} finally {
if (isMounted) {
setLoading(false);
}
}
};
loadUser();
return () => {
isMounted = false;
};
}, [userId, fetchUserData]);
return { user, loading, error };
};
`,
},
{
name: "utils/api.ts",
content: `
import { User } from '../types';
// Simulate API call with mock data
export const fetchUserData = async (userId: string): Promise<User> => {
// Simulate network delay
await new Promise(resolve => setTimeout(resolve, 1000));
// Mock data
const users: Record<string, User> = {
'1': {
id: '1',
name: 'John Doe',
email: 'john@example.com',
avatar: 'https://randomuser.me/api/portraits/men/32.jpg'
},
'2': {
id: '2',
name: 'Jane Smith',
email: 'jane@example.com',
avatar: 'https://randomuser.me/api/portraits/women/44.jpg'
}
};
const user = users[userId];
if (!user) {
throw new Error(\`User with ID \${userId} not found\`);
}
return user;
};
`,
},
{
name: "components/UserProfile.tsx",
content: `
import React from 'react';
import { useUser } from '../hooks/useUser';
import { User } from '../types';
interface UserProfileProps {
userId: string;
fetchUserData: (id: string) => Promise<User>;
}
const UserProfile = ({ userId, fetchUserData }: UserProfileProps) => {
const { user, loading, error } = useUser(userId, fetchUserData);
if (loading) {
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 animate-pulse">
<div className="flex items-center space-x-4">
<div className="rounded-full bg-gray-300 dark:bg-gray-600 h-16 w-16"></div>
<div className="flex-1 space-y-3">
<div className="h-4 bg-gray-300 dark:bg-gray-600 rounded w-3/4"></div>
<div className="h-3 bg-gray-300 dark:bg-gray-600 rounded w-1/2"></div>
</div>
</div>
</div>
);
}
if (error) {
return (
<div className="bg-red-100 dark:bg-red-900 border-l-4 border-red-500 text-red-700 dark:text-red-200 p-4 rounded">
<p>{error}</p>
</div>
);
}
if (!user) {
return <div>No user found</div>;
}
return (
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden">
<div className="p-6">
<div className="flex items-center space-x-4">
<img
src={user.avatar}
alt={user.name}
className="h-16 w-16 rounded-full border-2 border-indigo-500"
/>
<div>
<h2 className="text-xl font-bold text-gray-900 dark:text-white">{user.name}</h2>
<p className="text-gray-600 dark:text-gray-300">{user.email}</p>
</div>
</div>
</div>
<div className="bg-gray-50 dark:bg-gray-900 px-6 py-4">
<p className="text-sm text-gray-500 dark:text-gray-400">
User ID: {user.id}
</p>
</div>
</div>
);
};
export default UserProfile;
`,
},
];
function App() {
return (
<CodeExecutor
code={files}
config={{
enableTailwind: true,
}}
/>
);
}
import { CodeExecutor } from "react-exe";
function App() {
return (
<CodeExecutor
code={code}
config={{
enableTailwind: true,
errorClassName: "my-error-class",
errorStyle: {
background: "#fee2e2",
border: "2px solid #ef4444",
},
onError: (error) => {
console.error("Component error:", error);
// Send to error tracking service
trackError(error);
},
// Custom security patterns
securityPatterns: [
/localStorage/i,
/sessionStorage/i,
/window\.location/i,
],
}}
/>
);
}
The config
prop accepts the following options:
interface CodeExecutorConfig {
// External dependencies available to the rendered component
dependencies?: Record<string, any>;
// Enable Tailwind CSS support
enableTailwind?: boolean;
// Custom className for the container
containerClassName?: string;
// Custom inline styles for the container
containerStyle?: React.CSSProperties;
// Custom className for error messages
errorClassName?: string;
// Custom inline styles for error messages
errorStyle?: React.CSSProperties;
// Custom security patterns to block potentially malicious code
securityPatterns?: RegExp[];
// Error callback function
onError?: (error: Error) => void;
}
React-EXE accepts code in two formats:
-
Single File: Pass a string containing the React component code
// Single file as a string const code = ` export default function App() { return <div>Hello World</div>; } `;
-
Multiple Files: Pass an array of CodeFile objects:
// Multiple files const code = [ { name: "App.tsx", content: "import React from 'react';\nimport Button from './Button';\n...", isEntry: true, // Mark this as the entry point }, { name: "Button.tsx", content: "export default function Button() { return <button>Click me</button>; }", }, ];
The
CodeFile
interface:interface CodeFile { name: string; // File name with extension (used for imports) content: string; // File content isEntry?: boolean; // Whether this is the entry point (defaults to first file if not specified) }
React-EXE includes built-in security measures:
- Default security patterns to block potentially harmful code
- Custom security pattern support
- Error boundary protection
Default blocked patterns include:
const defaultSecurityPatterns = [
/document\.cookie/i,
/window\.document\.cookie/i,
/eval\(/i,
/Function\(/i,
/document\.write/i,
/document\.location/i,
];
React-EXE is written in TypeScript and includes type definitions. For the best development experience, use TypeScript in your project:
import { CodeExecutor, CodeExecutorConfig, CodeFile } from "react-exe";
const config: CodeExecutorConfig = {
enableTailwind: true,
dependencies: {
"my-component": MyComponent,
},
};
const files: CodeFile[] = [
{
name: "App.tsx",
content: `export default function App() { return <div>Hello</div>; }`,
isEntry: true,
},
];
function App() {
return <CodeExecutor code={files} config={config} />;
}
Used By TuneChat to render Artifacts

MIT © Vikrant
Made with ❤️ by Vikrant