or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

code-transformation.mdcontext-integration.mdindex.mdlive-components.mdstandalone-editor.md

standalone-editor.mddocs/

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

```