A production-focused playground for live editing React code with real-time preview capabilities
—
Independent code editor component with syntax highlighting that can be used outside of the live editing context. This component provides a rich editing experience for general-purpose code editing needs without the live execution functionality.
Standalone code editor component with syntax highlighting, configurable themes, and customizable behavior. Built on top of Prism.js for syntax highlighting and use-editable for editing functionality.
/**
* Standalone code editor component with syntax highlighting
* @param props - Editor configuration and behavior options
*/
function Editor(props: {
/** CSS class name for the editor wrapper */
className?: string;
/** Code content to display and edit */
code: string;
/** Whether editing is disabled (read-only mode) */
disabled?: boolean;
/** Language identifier for syntax highlighting */
language: string;
/** Custom Prism instance for syntax highlighting */
prism?: typeof Prism;
/** Custom CSS styles for the editor wrapper */
style?: CSSProperties;
/** Tab key behavior: "focus" moves focus, "indentation" adds spaces */
tabMode?: "focus" | "indentation";
/** Prism theme for syntax highlighting */
theme?: typeof themes.nightOwl;
/** Callback function called when code content changes */
onChange?(value: string): void;
}): JSX.Element;Usage Examples:
import React, { useState } from "react";
import { Editor } from "react-live";
import { themes, Prism } from "prism-react-renderer";
// Basic standalone editor
function BasicEditor() {
const [code, setCode] = useState('console.log("Hello World");');
return (
<Editor
code={code}
language="javascript"
onChange={setCode}
/>
);
}
// TypeScript editor with custom theme
function TypeScriptEditor() {
const [code, setCode] = useState(`
interface User {
name: string;
age: number;
}
const user: User = {
name: "Alice",
age: 30
};
`);
return (
<Editor
code={code}
language="typescript"
theme={themes.dracula}
onChange={setCode}
style={{
fontFamily: 'Monaco, Consolas, monospace',
fontSize: 14,
border: '1px solid #ccc',
borderRadius: 4
}}
/>
);
}
// Read-only code display
function CodeDisplay({ code, language }: { code: string; language: string }) {
return (
<Editor
code={code}
language={language}
disabled={true}
theme={themes.github}
className="read-only-editor"
/>
);
}
// Multi-language editor with language switcher
function MultiLanguageEditor() {
const [language, setLanguage] = useState('javascript');
const [code, setCode] = useState({
javascript: 'console.log("Hello from JavaScript");',
typescript: 'console.log("Hello from TypeScript" as string);',
jsx: '<div>Hello from JSX</div>',
css: '.hello { color: blue; }'
});
const currentCode = code[language as keyof typeof code];
const handleCodeChange = (newCode: string) => {
setCode(prev => ({
...prev,
[language]: newCode
}));
};
return (
<div className="multi-lang-editor">
<div className="language-selector">
{Object.keys(code).map(lang => (
<button
key={lang}
onClick={() => setLanguage(lang)}
className={language === lang ? 'active' : ''}
>
{lang}
</button>
))}
</div>
<Editor
code={currentCode}
language={language}
onChange={handleCodeChange}
tabMode="indentation"
theme={themes.vsDark}
/>
</div>
);
}
// Editor with custom tab behavior
function CustomTabEditor() {
const [code, setCode] = useState('function example() {\n // Add your code here\n}');
const [tabMode, setTabMode] = useState<"focus" | "indentation">("indentation");
return (
<div>
<div className="tab-controls">
<label>
<input
type="radio"
checked={tabMode === "indentation"}
onChange={() => setTabMode("indentation")}
/>
Tab for indentation
</label>
<label>
<input
type="radio"
checked={tabMode === "focus"}
onChange={() => setTabMode("focus")}
/>
Tab to move focus
</label>
</div>
<Editor
code={code}
language="javascript"
tabMode={tabMode}
onChange={setCode}
/>
</div>
);
}
// Editor with external save/load functionality
function FileEditor() {
const [code, setCode] = useState('');
const [filename, setFilename] = useState('untitled.js');
const [language, setLanguage] = useState('javascript');
const handleSave = () => {
const blob = new Blob([code], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
URL.revokeObjectURL(url);
};
const handleLoad = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
const content = e.target?.result as string;
setCode(content);
setFilename(file.name);
// Auto-detect language from file extension
const ext = file.name.split('.').pop()?.toLowerCase();
if (ext === 'ts' || ext === 'tsx') setLanguage('typescript');
else if (ext === 'jsx') setLanguage('jsx');
else if (ext === 'css') setLanguage('css');
else if (ext === 'html') setLanguage('html');
else setLanguage('javascript');
};
reader.readAsText(file);
}
};
return (
<div className="file-editor">
<div className="file-controls">
<input
type="text"
value={filename}
onChange={(e) => setFilename(e.target.value)}
placeholder="Filename"
/>
<input
type="file"
onChange={handleLoad}
accept=".js,.ts,.jsx,.tsx,.css,.html"
/>
<button onClick={handleSave} disabled={!code}>
Save
</button>
</div>
<Editor
code={code}
language={language}
onChange={setCode}
theme={themes.nightOwl}
style={{ height: 400 }}
className="file-editor-content"
/>
<div className="file-info">
<span>Language: {language}</span>
<span>Lines: {code.split('\n').length}</span>
<span>Characters: {code.length}</span>
</div>
</div>
);
}
// Code comparison editor
function CodeComparison({
originalCode,
modifiedCode,
language
}: {
originalCode: string;
modifiedCode: string;
language: string;
}) {
return (
<div className="code-comparison">
<div className="comparison-pane">
<h4>Original</h4>
<Editor
code={originalCode}
language={language}
disabled={true}
theme={themes.github}
/>
</div>
<div className="comparison-pane">
<h4>Modified</h4>
<Editor
code={modifiedCode}
language={language}
disabled={true}
theme={themes.github}
/>
</div>
</div>
);
}The editor supports all themes from prism-react-renderer:
import { themes, Prism } from "prism-react-renderer";
// Available themes
const availableThemes = {
dracula: themes.dracula,
duotoneDark: themes.duotoneDark,
duotoneLight: themes.duotoneLight,
github: themes.github,
nightOwl: themes.nightOwl,
nightOwlLight: themes.nightOwlLight,
oceanicNext: themes.oceanicNext,
okaidia: themes.okaidia,
palenight: themes.palenight,
prism: themes.prism,
shadesOfPurple: themes.shadesOfPurple,
synthwave84: themes.synthwave84,
ultramin: themes.ultramin,
vsDark: themes.vsDark,
vsLight: themes.vsLight
};
// Theme selector component
function ThemeSelector({
currentTheme,
onThemeChange
}: {
currentTheme: string;
onThemeChange: (theme: any) => void;
}) {
return (
<select
value={currentTheme}
onChange={(e) => onThemeChange(availableThemes[e.target.value as keyof typeof availableThemes])}
>
{Object.keys(availableThemes).map(themeName => (
<option key={themeName} value={themeName}>
{themeName}
</option>
))}
</select>
);
}The editor supports syntax highlighting for many languages through Prism.js:
// Common language identifiers
const supportedLanguages = [
'javascript', 'typescript', 'jsx', 'tsx',
'css', 'scss', 'sass', 'less',
'html', 'xml', 'svg',
'json', 'yaml', 'toml',
'markdown', 'mdx',
'python', 'java', 'csharp', 'cpp', 'c',
'php', 'ruby', 'go', 'rust',
'sql', 'graphql',
'bash', 'shell', 'powershell',
'dockerfile', 'nginx',
'regex'
];
// Language detection utility
function detectLanguage(filename: string): string {
const ext = filename.split('.').pop()?.toLowerCase();
const languageMap: Record<string, string> = {
'js': 'javascript',
'mjs': 'javascript',
'ts': 'typescript',
'tsx': 'tsx',
'jsx': 'jsx',
'css': 'css',
'scss': 'scss',
'sass': 'sass',
'less': 'less',
'html': 'html',
'htm': 'html',
'xml': 'xml',
'svg': 'svg',
'json': 'json',
'yaml': 'yaml',
'yml': 'yaml',
'toml': 'toml',
'md': 'markdown',
'mdx': 'mdx',
'py': 'python',
'java': 'java',
'cs': 'csharp',
'cpp': 'cpp',
'cc': 'cpp',
'cxx': 'cpp',
'c': 'c',
'h': 'c',
'php': 'php',
'rb': 'ruby',
'go': 'go',
'rs': 'rust',
'sql': 'sql',
'graphql': 'graphql',
'gql': 'graphql',
'sh': 'bash',
'bash': 'bash',
'zsh': 'bash',
'ps1': 'powershell',
'dockerfile': 'dockerfile'
};
return languageMap[ext || ''] || 'text';
}// React Hook Form integration
import { useController, Control } from "react-hook-form";
function CodeFormField({
name,
control,
language,
rules
}: {
name: string;
control: Control;
language: string;
rules?: any;
}) {
const { field, fieldState } = useController({
name,
control,
rules
});
return (
<div className="code-form-field">
<Editor
code={field.value || ''}
language={language}
onChange={field.onChange}
className={fieldState.error ? 'error' : ''}
/>
{fieldState.error && (
<span className="error-message">{fieldState.error.message}</span>
)}
</div>
);
}
// Formik integration
import { Field, FieldProps } from "formik";
function FormikCodeField({
name,
language
}: {
name: string;
language: string;
}) {
return (
<Field name={name}>
{({ field, meta }: FieldProps) => (
<div className="formik-code-field">
<Editor
code={field.value || ''}
language={language}
onChange={(value) => field.onChange({ target: { name, value } })}
className={meta.touched && meta.error ? 'error' : ''}
/>
{meta.touched && meta.error && (
<div className="error-message">{meta.error}</div>
)}
</div>
)}
</Field>
);
}// Redux integration
import { useDispatch, useSelector } from "react-redux";
function ReduxCodeEditor({ editorId }: { editorId: string }) {
const dispatch = useDispatch();
const code = useSelector(state => state.editors[editorId]?.code || '');
const language = useSelector(state => state.editors[editorId]?.language || 'javascript');
const handleChange = (newCode: string) => {
dispatch({
type: 'UPDATE_EDITOR_CODE',
payload: { editorId, code: newCode }
});
};
return (
<Editor
code={code}
language={language}
onChange={handleChange}
/>
);
}
// Zustand integration
import { create } from "zustand";
const useEditorStore = create((set) => ({
editors: {},
updateEditor: (id: string, updates: any) =>
set((state) => ({
editors: {
...state.editors,
[id]: { ...state.editors[id], ...updates }
}
}))
}));
function ZustandCodeEditor({ editorId }: { editorId: string }) {
const editor = useEditorStore(state => state.editors[editorId] || {});
const updateEditor = useEditorStore(state => state.updateEditor);
return (
<Editor
code={editor.code || ''}
language={editor.language || 'javascript'}
onChange={(code) => updateEditor(editorId, { code })}
/>
);
}Install with Tessl CLI
npx tessl i tessl/npm-react-live