src/main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
import './styles.css'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
Online Radix UI playground with React, TypeScript, accessible unstyled primitives, editable component files, and instant live preview.
Choose a source file from the explorer and edit it with Monaco.
Edit package.json to add browser-compatible npm packages or change versions. Preview packages load from esm.sh. Successful previews save resolved versions for ranges and tags with your draft and shares; change the range to resolve again. Scripts and build plugins run only in downloaded projects.
Auto-run updates the browser preview as you type. Turn it off to run your changes manually.
Use the console for browser logs and errors, or evaluate a command against the preview.
Share creates a snapshot link. Download exports the source so you can continue locally.
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
import './styles.css'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)
import { useState } from 'react'
import { Dialog, Switch, Tabs } from 'radix-ui'
import { ActivityCard } from './components/ActivityCard'
const activity = [
{ title: 'Navigation menu', detail: 'Keyboard flow reviewed', status: 'Ready' },
{ title: 'Settings dialog', detail: 'Focus trap verified', status: 'Ready' },
{ title: 'Account switcher', detail: 'Labels need review', status: 'Review' },
]
export default function App() {
const [notifications, setNotifications] = useState(true)
const [saved, setSaved] = useState(false)
const savePreferences = () => {
setSaved(true)
window.setTimeout(() => setSaved(false), 1800)
}
return (
<main className="app-shell">
<section className="workspace" aria-labelledby="page-title">
<header className="page-header">
<div className="brand-mark" aria-hidden="true">
<span />
<span />
<span />
</div>
<div className="heading-copy">
<p className="eyebrow">RADIX PRIMITIVES · REACT 19</p>
<h1 id="page-title">Interface health</h1>
<p>Accessible building blocks, composed into a real product surface.</p>
</div>
<span className="status-pill"><i /> All systems ready</span>
</header>
<Tabs.Root className="tabs" defaultValue="overview">
<Tabs.List className="tabs-list" aria-label="Interface health sections">
<Tabs.Trigger className="tabs-trigger" value="overview">Overview</Tabs.Trigger>
<Tabs.Trigger className="tabs-trigger" value="activity">Activity</Tabs.Trigger>
</Tabs.List>
<Tabs.Content className="tabs-content" value="overview">
<div className="summary-grid">
<article className="metric-card">
<span>Accessibility score</span>
<strong>98</strong>
<small>+4 this release</small>
</article>
<article className="metric-card">
<span>Primitives in use</span>
<strong>12</strong>
<small>Across 7 flows</small>
</article>
<article className="metric-card">
<span>Open reviews</span>
<strong>3</strong>
<small>2 due today</small>
</article>
</div>
<div className="settings-card">
<div>
<h2>Release notifications</h2>
<p>Get an update when accessibility reviews are complete.</p>
</div>
<Switch.Root
className="switch-root"
checked={notifications}
onCheckedChange={setNotifications}
aria-label="Release notifications"
>
<Switch.Thumb className="switch-thumb" />
</Switch.Root>
</div>
</Tabs.Content>
<Tabs.Content className="tabs-content" value="activity">
<div className="activity-list">
{activity.map((item) => <ActivityCard key={item.title} {...item} />)}
</div>
</Tabs.Content>
</Tabs.Root>
<Dialog.Root>
<Dialog.Trigger asChild>
<button className="primary-button">Review preferences</button>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="dialog-overlay" />
<Dialog.Content className="dialog-content">
<Dialog.Title>Notification preferences</Dialog.Title>
<Dialog.Description>
Choose whether this workspace should send release review updates.
</Dialog.Description>
<label className="dialog-setting">
<span>
<strong>Release notifications</strong>
<small>{notifications ? 'Currently enabled' : 'Currently disabled'}</small>
</span>
<Switch.Root
className="switch-root"
checked={notifications}
onCheckedChange={setNotifications}
aria-label="Dialog release notifications"
>
<Switch.Thumb className="switch-thumb" />
</Switch.Root>
</label>
<div className="dialog-actions">
<Dialog.Close asChild>
<button className="secondary-button">Cancel</button>
</Dialog.Close>
<Dialog.Close asChild>
<button className="primary-button" onClick={savePreferences}>
Save preferences
</button>
</Dialog.Close>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<p className="save-status" aria-live="polite">
{saved ? 'Preferences saved.' : ''}
</p>
</section>
</main>
)
}
The editor uses Monaco, the engine behind VS Code, with language-aware editing tools and familiar keyboard controls.
Edit a source file from the project explorer — the live preview recompiles automatically.
Add, rename, duplicate or delete project files as needed. Update affected imports after renaming or moving a file.
Use the console for logs and errors, and Format to tidy the active file.
Share the complete project or download a Vite project ZIP with its source files and package.json.
Radix UI 1.6
React 19 + TypeScript
Accessible Primitives
Keyboard Navigation
Focus Management
Local Component Imports
Live Preview
Vite Project Export
Auto-run updates the preview as you type. Turn it off to run manually with Run or Ctrl/⌘ + Enter.
The Console prompt can inspect browser globals and the rendered DOM, but not variables scoped inside ES modules or component state.
Console shortcuts apply when its prompt is focused. Editor shortcuts apply inside the code editor.
Code runs in a sandboxed browser preview, without Node.js, a backend, or private environment variables.
Download the project when you need build plugins, server APIs, native modules, or a production dependency workflow.