Skip to content
Inputs

Code Editor

A code editor with no editor in it.

Walkthrough

1. Basic

It is a real <textarea> with a highlighted copy painted behind it, so Tab indents, Enter keeps your indentation, brackets close themselves and ⌘Z still walks back one edit at a time. Type in it.

utils.ts TypeScript
<script lang="ts">	import { CodeEditor } from 'omaris';​	let value = $state(`export function cn(...inputs: ClassValue[]) {	return twMerge(clsx(inputs));}`);</script>​<CodeEditor bind:value lang="ts" title="utils.ts" height={220} class="w-full" />

2. Copy

copy puts a copy button in the header, or floats one when there is no header.

slugify.ts TypeScript
<script lang="ts">	import { CodeEditor } from 'omaris';​	let withHeader = $state(`export function slugify(text) {	return text		.toLowerCase()		.replace(/[^a-z0-9]+/g, '-')		.replace(/^-|-$/g, '');}`);​	let bare = $state(`const total = items.reduce((sum, item) => sum + item.price, 0);`);</script>​<div class="flex flex-col gap-5">	<CodeEditor bind:value={withHeader} lang="ts" title="slugify.ts" copy height={160} />​	<!-- No title, so the button floats over the corner: quiet until the	     pointer arrives, and always there on a touch screen. Select a few	     lines first and it copies the selection instead of the file. -->	<CodeEditor bind:value={bare} lang="ts" copy height={96} lineNumbers={false} /></div>

3. Vim

vim is the whole integration. Click in and you are in normal mode — the status bar says which one you are in and echoes the half-typed command. Counts, operators and motions (d2w, ci", >ip, gUiw, gcc), registers, marks, / search, ., <C-a>, and an ex line with :w, :%s/a/b/g and :set rnu. u undoes a whole command, not a keystroke.

total.ts TypeScript
NORMAL Ln 1, Col 1 8 lines 99 chars
mode normal · :w written 0 times
<script lang="ts">	import { CodeEditor, Text, type VimMode } from 'omaris';​	let mode = $state<VimMode>('normal');	let writes = $state(0);​	let value = $state(`export function total(list) {	let sum = 0;	for (const n of list) {		sum += n;	}	return sum;}`);</script>​<div class="flex w-full flex-col gap-2">	<CodeEditor		bind:value		bind:vimMode={mode}		lang="ts"		vim		title="total.ts"		insertSpaces={false}		height={240}		onsave={() => writes++}	/>	<Text variant="label-sm" tone="muted">		mode {mode} · :w written {writes}		{writes === 1 ? 'time' : 'times'}	</Text></div>

4. Status and read only

status puts line, column and length along the bottom. readOnly keeps the colouring and the gutter but refuses edits, and startLine numbers a snippet from wherever it really begins.

package.json JSON
Ln 1, Col 1 5 lines 85 chars
read-only, numbered from 118
<script lang="ts">	import { CodeEditor, Text } from 'omaris';​	let json = $state(`{	"name": "omaris",	"type": "module",	"peerDependencies": { "svelte": "^5.0.0" }}`);​	const EXCERPT = `.dark {	--surface: oklch(0.21 0.01 260);	--surface-container: oklch(0.26 0.012 260);}`;</script>​<div class="flex w-full flex-col gap-4">	<CodeEditor bind:value={json} lang="json" title="package.json" status height="9rem" />​	<div class="flex flex-col gap-1">		<Text variant="label-sm" tone="muted">read-only, numbered from 118</Text>		<CodeEditor			value={EXCERPT}			lang="css"			readOnly			size="sm"			startLine={118}			highlightActiveLine={false}			height="7rem"		/>	</div></div>

5. Find and diagnostics

⌘F finds and ⌘H replaces — every hit is drawn behind the text, so the count in the panel and the marks in the file agree. markers puts a rule under a span, colours its gutter number, and shows the message in the status bar while the caret is on that line. ⌃Space completes.

totals.ts TypeScript
Ln 1, Col 1 4 lines 80 chars
<script lang="ts">	import { CodeEditor } from 'omaris';​	let value = $state(`const total = items.reduce((a, b) => a + b);let unused = 2;console.log(totl);`);</script>​<CodeEditor	bind:value	lang="ts"	title="totals.ts"	height={190}	status	completions={['items', 'total', 'reduce', 'console']}	markers={[		{			line: 2,			column: 5,			endColumn: 11,			severity: 'warning',			message: "'unused' is declared but never read"		},		{			line: 3,			column: 13,			endColumn: 17,			severity: 'error',			message: "Cannot find name 'totl'. Did you mean 'total'?"		}	]}	class="w-full"/>

6. Overridden

height lives in a custom property rather than a class, so height="auto" plus a min-h-* on classes.frame lets the editor grow with its content instead of scrolling. wrap stops the sideways scroll, and the gutter can go.

<script lang="ts">	import { CodeEditor } from 'omaris';​	let value = $state(		`# every line here is long enough to prove that wrapping is on rather than a horizontal scrollbar\nbun run check && bun run lint && bun run reference`	);</script>​<CodeEditor	bind:value	lang="bash"	wrap	lineNumbers={false}	tabSize={4}	autoClose={false}	height="auto"	classes={{		root: 'rounded-shape-lg border-primary/40',		frame: 'min-h-24',		input: 'caret-primary'	}}	class="w-full"/>