Skip to content
Inputs

Inline Edit

Click the text, it becomes a field. Nothing on the page moves.

Walkthrough

1. Basic

Click the title. The line under it does not move: the reading view, the input and an invisible copy of the text all share one grid cell.

This line stays exactly where it is.

<script lang="ts">	import { InlineEdit } from 'omaris';​	let title = $state('Untitled board');</script>​<div class="w-96 max-w-full rounded-shape-md border border-border p-4">	<InlineEdit bind:value={title} label="Board name" class="text-xl font-semibold" />	<p class="pt-2 text-sm text-muted-foreground">This line stays exactly where it is.</p></div>

2. Multiline

A textarea that grows by the line. Enter is a newline here, ⌘/Ctrl+Enter saves, Escape cancels.

<script lang="ts">	import { InlineEdit } from 'omaris';​	let note = $state('Two lines of notes,\nand the box grows with them.');	let empty = $state('');</script>​<div class="flex w-96 max-w-full flex-col gap-4">	<InlineEdit bind:value={note} multiline block label="Notes" />	<InlineEdit bind:value={empty} placeholder="Add a description" block label="Description" /></div>

3. Async

A save that can fail. The value is only written once the promise settles, so a rejection leaves the field open on what was typed — with the reason floating under it, where it cannot push the page around.

<script lang="ts">	import { InlineEdit } from 'omaris';​	let name = $state('Anything but "no"');​	async function save(next: string) {		await new Promise((resolve) => setTimeout(resolve, 800));		if (next.toLowerCase() === 'no') throw new Error('That name is taken');	}</script>​<div class="w-80 max-w-full">	<InlineEdit		bind:value={name}		label="Name"		onsave={save}		validate={(next) => (next.length < 2 ? 'At least two characters' : null)}	/></div>

4. Overridden

A right-aligned figure in a table row: monospace, tabular, no pencil.

Revenue
Cost
<script lang="ts">	import { InlineEdit } from 'omaris';​	let revenue = $state('12 500');	let cost = $state('4 200');</script>​<div class="w-64 max-w-full overflow-hidden rounded-shape-md border border-border">	{#each [{ label: 'Revenue', get: () => revenue, set: (v: string) => void (revenue = v) }, { label: 'Cost', get: () => cost, set: (v: string) => void (cost = v) }] as row (row.label)}		<div class="flex items-center justify-between border-b border-border px-3 py-2 last:border-b-0">			<span class="text-sm text-muted-foreground">{row.label}</span>			<InlineEdit				value={row.get()}				onsave={row.set}				align="end"				size="sm"				pencil={false}				label={row.label}				class="font-mono tabular-nums"				classes={{ view: 'hover:bg-primary/10' }}			/>		</div>	{/each}</div>