0
# Standalone Editor
1
2
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.
3
4
## Capabilities
5
6
### Editor
7
8
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.
9
10
```typescript { .api }
11
/**
12
* Standalone code editor component with syntax highlighting
13
* @param props - Editor configuration and behavior options
14
*/
15
function Editor(props: {
16
/** CSS class name for the editor wrapper */
17
className?: string;
18
/** Code content to display and edit */
19
code: string;
20
/** Whether editing is disabled (read-only mode) */
21
disabled?: boolean;
22
/** Language identifier for syntax highlighting */
23
language: string;
24
/** Custom Prism instance for syntax highlighting */
25
prism?: typeof Prism;
26
/** Custom CSS styles for the editor wrapper */
27
style?: CSSProperties;
28
/** Tab key behavior: "focus" moves focus, "indentation" adds spaces */
29
tabMode?: "focus" | "indentation";
30
/** Prism theme for syntax highlighting */
31
theme?: typeof themes.nightOwl;
32
/** Callback function called when code content changes */
33
onChange?(value: string): void;
34
}): JSX.Element;
35
```
36
37
**Usage Examples:**
38
39
```typescript
40
import React, { useState } from "react";
41
import { Editor } from "react-live";
42
import { themes, Prism } from "prism-react-renderer";
43
44
// Basic standalone editor
45
function BasicEditor() {
46
const [code, setCode] = useState('console.log("Hello World");');
47
48
return (
49
<Editor
50
code={code}
51
language="javascript"
52
onChange={setCode}
53
/>
54
);
55
}
56
57
// TypeScript editor with custom theme
58
function TypeScriptEditor() {
59
const [code, setCode] = useState(`
60
interface User {
61
name: string;
62
age: number;
63
}
64
65
const user: User = {
66
name: "Alice",
67
age: 30
68
};
69
`);
70
71
return (
72
<Editor
73
code={code}
74
language="typescript"
75
theme={themes.dracula}
76
onChange={setCode}
77
style={{
78
fontFamily: 'Monaco, Consolas, monospace',
79
fontSize: 14,
80
border: '1px solid #ccc',
81
borderRadius: 4
82
}}
83
/>
84
);
85
}
86
87
// Read-only code display
88
function CodeDisplay({ code, language }: { code: string; language: string }) {
89
return (
90
<Editor
91
code={code}
92
language={language}
93
disabled={true}
94
theme={themes.github}
95
className="read-only-editor"
96
/>
97
);
98
}
99
100
// Multi-language editor with language switcher
101
function MultiLanguageEditor() {
102
const [language, setLanguage] = useState('javascript');
103
const [code, setCode] = useState({
104
javascript: 'console.log("Hello from JavaScript");',
105
typescript: 'console.log("Hello from TypeScript" as string);',
106
jsx: '<div>Hello from JSX</div>',
107
css: '.hello { color: blue; }'
108
});
109
110
const currentCode = code[language as keyof typeof code];
111
112
const handleCodeChange = (newCode: string) => {
113
setCode(prev => ({
114
...prev,
115
[language]: newCode
116
}));
117
};
118
119
return (
120
<div className="multi-lang-editor">
121
<div className="language-selector">
122
{Object.keys(code).map(lang => (
123
<button
124
key={lang}
125
onClick={() => setLanguage(lang)}
126
className={language === lang ? 'active' : ''}
127
>
128
{lang}
129
</button>
130
))}
131
</div>
132
<Editor
133
code={currentCode}
134
language={language}
135
onChange={handleCodeChange}
136
tabMode="indentation"
137
theme={themes.vsDark}
138
/>
139
</div>
140
);
141
}
142
143
// Editor with custom tab behavior
144
function CustomTabEditor() {
145
const [code, setCode] = useState('function example() {\n // Add your code here\n}');
146
const [tabMode, setTabMode] = useState<"focus" | "indentation">("indentation");
147
148
return (
149
<div>
150
<div className="tab-controls">
151
<label>
152
<input
153
type="radio"
154
checked={tabMode === "indentation"}
155
onChange={() => setTabMode("indentation")}
156
/>
157
Tab for indentation
158
</label>
159
<label>
160
<input
161
type="radio"
162
checked={tabMode === "focus"}
163
onChange={() => setTabMode("focus")}
164
/>
165
Tab to move focus
166
</label>
167
</div>
168
<Editor
169
code={code}
170
language="javascript"
171
tabMode={tabMode}
172
onChange={setCode}
173
/>
174
</div>
175
);
176
}
177
178
// Editor with external save/load functionality
179
function FileEditor() {
180
const [code, setCode] = useState('');
181
const [filename, setFilename] = useState('untitled.js');
182
const [language, setLanguage] = useState('javascript');
183
184
const handleSave = () => {
185
const blob = new Blob([code], { type: 'text/plain' });
186
const url = URL.createObjectURL(blob);
187
const link = document.createElement('a');
188
link.href = url;
189
link.download = filename;
190
link.click();
191
URL.revokeObjectURL(url);
192
};
193
194
const handleLoad = (event: React.ChangeEvent<HTMLInputElement>) => {
195
const file = event.target.files?.[0];
196
if (file) {
197
const reader = new FileReader();
198
reader.onload = (e) => {
199
const content = e.target?.result as string;
200
setCode(content);
201
setFilename(file.name);
202
203
// Auto-detect language from file extension
204
const ext = file.name.split('.').pop()?.toLowerCase();
205
if (ext === 'ts' || ext === 'tsx') setLanguage('typescript');
206
else if (ext === 'jsx') setLanguage('jsx');
207
else if (ext === 'css') setLanguage('css');
208
else if (ext === 'html') setLanguage('html');
209
else setLanguage('javascript');
210
};
211
reader.readAsText(file);
212
}
213
};
214
215
return (
216
<div className="file-editor">
217
<div className="file-controls">
218
<input
219
type="text"
220
value={filename}
221
onChange={(e) => setFilename(e.target.value)}
222
placeholder="Filename"
223
/>
224
<input
225
type="file"
226
onChange={handleLoad}
227
accept=".js,.ts,.jsx,.tsx,.css,.html"
228
/>
229
<button onClick={handleSave} disabled={!code}>
230
Save
231
</button>
232
</div>
233
234
<Editor
235
code={code}
236
language={language}
237
onChange={setCode}
238
theme={themes.nightOwl}
239
style={{ height: 400 }}
240
className="file-editor-content"
241
/>
242
243
<div className="file-info">
244
<span>Language: {language}</span>
245
<span>Lines: {code.split('\n').length}</span>
246
<span>Characters: {code.length}</span>
247
</div>
248
</div>
249
);
250
}
251
252
// Code comparison editor
253
function CodeComparison({
254
originalCode,
255
modifiedCode,
256
language
257
}: {
258
originalCode: string;
259
modifiedCode: string;
260
language: string;
261
}) {
262
return (
263
<div className="code-comparison">
264
<div className="comparison-pane">
265
<h4>Original</h4>
266
<Editor
267
code={originalCode}
268
language={language}
269
disabled={true}
270
theme={themes.github}
271
/>
272
</div>
273
<div className="comparison-pane">
274
<h4>Modified</h4>
275
<Editor
276
code={modifiedCode}
277
language={language}
278
disabled={true}
279
theme={themes.github}
280
/>
281
</div>
282
</div>
283
);
284
}
285
```
286
287
## Customization Options
288
289
### Themes
290
291
The editor supports all themes from `prism-react-renderer`:
292
293
```typescript
294
import { themes, Prism } from "prism-react-renderer";
295
296
// Available themes
297
const availableThemes = {
298
dracula: themes.dracula,
299
duotoneDark: themes.duotoneDark,
300
duotoneLight: themes.duotoneLight,
301
github: themes.github,
302
nightOwl: themes.nightOwl,
303
nightOwlLight: themes.nightOwlLight,
304
oceanicNext: themes.oceanicNext,
305
okaidia: themes.okaidia,
306
palenight: themes.palenight,
307
prism: themes.prism,
308
shadesOfPurple: themes.shadesOfPurple,
309
synthwave84: themes.synthwave84,
310
ultramin: themes.ultramin,
311
vsDark: themes.vsDark,
312
vsLight: themes.vsLight
313
};
314
315
// Theme selector component
316
function ThemeSelector({
317
currentTheme,
318
onThemeChange
319
}: {
320
currentTheme: string;
321
onThemeChange: (theme: any) => void;
322
}) {
323
return (
324
<select
325
value={currentTheme}
326
onChange={(e) => onThemeChange(availableThemes[e.target.value as keyof typeof availableThemes])}
327
>
328
{Object.keys(availableThemes).map(themeName => (
329
<option key={themeName} value={themeName}>
330
{themeName}
331
</option>
332
))}
333
</select>
334
);
335
}
336
```
337
338
### Supported Languages
339
340
The editor supports syntax highlighting for many languages through Prism.js:
341
342
```typescript
343
// Common language identifiers
344
const supportedLanguages = [
345
'javascript', 'typescript', 'jsx', 'tsx',
346
'css', 'scss', 'sass', 'less',
347
'html', 'xml', 'svg',
348
'json', 'yaml', 'toml',
349
'markdown', 'mdx',
350
'python', 'java', 'csharp', 'cpp', 'c',
351
'php', 'ruby', 'go', 'rust',
352
'sql', 'graphql',
353
'bash', 'shell', 'powershell',
354
'dockerfile', 'nginx',
355
'regex'
356
];
357
358
// Language detection utility
359
function detectLanguage(filename: string): string {
360
const ext = filename.split('.').pop()?.toLowerCase();
361
362
const languageMap: Record<string, string> = {
363
'js': 'javascript',
364
'mjs': 'javascript',
365
'ts': 'typescript',
366
'tsx': 'tsx',
367
'jsx': 'jsx',
368
'css': 'css',
369
'scss': 'scss',
370
'sass': 'sass',
371
'less': 'less',
372
'html': 'html',
373
'htm': 'html',
374
'xml': 'xml',
375
'svg': 'svg',
376
'json': 'json',
377
'yaml': 'yaml',
378
'yml': 'yaml',
379
'toml': 'toml',
380
'md': 'markdown',
381
'mdx': 'mdx',
382
'py': 'python',
383
'java': 'java',
384
'cs': 'csharp',
385
'cpp': 'cpp',
386
'cc': 'cpp',
387
'cxx': 'cpp',
388
'c': 'c',
389
'h': 'c',
390
'php': 'php',
391
'rb': 'ruby',
392
'go': 'go',
393
'rs': 'rust',
394
'sql': 'sql',
395
'graphql': 'graphql',
396
'gql': 'graphql',
397
'sh': 'bash',
398
'bash': 'bash',
399
'zsh': 'bash',
400
'ps1': 'powershell',
401
'dockerfile': 'dockerfile'
402
};
403
404
return languageMap[ext || ''] || 'text';
405
}
406
```
407
408
## Integration Patterns
409
410
### With Form Libraries
411
412
```typescript
413
// React Hook Form integration
414
import { useController, Control } from "react-hook-form";
415
416
function CodeFormField({
417
name,
418
control,
419
language,
420
rules
421
}: {
422
name: string;
423
control: Control;
424
language: string;
425
rules?: any;
426
}) {
427
const { field, fieldState } = useController({
428
name,
429
control,
430
rules
431
});
432
433
return (
434
<div className="code-form-field">
435
<Editor
436
code={field.value || ''}
437
language={language}
438
onChange={field.onChange}
439
className={fieldState.error ? 'error' : ''}
440
/>
441
{fieldState.error && (
442
<span className="error-message">{fieldState.error.message}</span>
443
)}
444
</div>
445
);
446
}
447
448
// Formik integration
449
import { Field, FieldProps } from "formik";
450
451
function FormikCodeField({
452
name,
453
language
454
}: {
455
name: string;
456
language: string;
457
}) {
458
return (
459
<Field name={name}>
460
{({ field, meta }: FieldProps) => (
461
<div className="formik-code-field">
462
<Editor
463
code={field.value || ''}
464
language={language}
465
onChange={(value) => field.onChange({ target: { name, value } })}
466
className={meta.touched && meta.error ? 'error' : ''}
467
/>
468
{meta.touched && meta.error && (
469
<div className="error-message">{meta.error}</div>
470
)}
471
</div>
472
)}
473
</Field>
474
);
475
}
476
```
477
478
### With State Management
479
480
```typescript
481
// Redux integration
482
import { useDispatch, useSelector } from "react-redux";
483
484
function ReduxCodeEditor({ editorId }: { editorId: string }) {
485
const dispatch = useDispatch();
486
const code = useSelector(state => state.editors[editorId]?.code || '');
487
const language = useSelector(state => state.editors[editorId]?.language || 'javascript');
488
489
const handleChange = (newCode: string) => {
490
dispatch({
491
type: 'UPDATE_EDITOR_CODE',
492
payload: { editorId, code: newCode }
493
});
494
};
495
496
return (
497
<Editor
498
code={code}
499
language={language}
500
onChange={handleChange}
501
/>
502
);
503
}
504
505
// Zustand integration
506
import { create } from "zustand";
507
508
const useEditorStore = create((set) => ({
509
editors: {},
510
updateEditor: (id: string, updates: any) =>
511
set((state) => ({
512
editors: {
513
...state.editors,
514
[id]: { ...state.editors[id], ...updates }
515
}
516
}))
517
}));
518
519
function ZustandCodeEditor({ editorId }: { editorId: string }) {
520
const editor = useEditorStore(state => state.editors[editorId] || {});
521
const updateEditor = useEditorStore(state => state.updateEditor);
522
523
return (
524
<Editor
525
code={editor.code || ''}
526
language={editor.language || 'javascript'}
527
onChange={(code) => updateEditor(editorId, { code })}
528
/>
529
);
530
}
531
```