Inline Edit
Click-to-edit text that swaps between a static value and an editable input. Saves on Enter, cancels on Escape, blurs to commit — the canonical pattern from Notion and Linear.
Inline Edit the 23rd of 28 designs in the 28 CSS Input Field Designs collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
The code
<label class="if-edit">
<span class="if-edit-label">Project name</span>
<span class="if-edit-wrap" data-if-edit data-value="Aurora Dashboard">
<span class="if-edit-display" tabindex="0" role="button" aria-label="Edit project name"
>Aurora Dashboard</span
>
<input class="if-edit-input" type="text" value="Aurora Dashboard" hidden />
<span class="if-edit-pencil" aria-hidden="true">✎</span>
</span>
</label> .if-edit {
display: grid;
gap: 6px;
width: 100%;
max-width: 280px;
}
.if-edit-label {
font-family: "JetBrains Mono", monospace;
font-size: 10px;
letter-spacing: 0.12em;
color: #b8b6d4;
text-transform: uppercase;
}
.if-edit-wrap {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
background: transparent;
border: 1px dashed transparent;
border-radius: 8px;
cursor: text;
transition:
background 0.15s,
border-color 0.15s;
}
.if-edit-wrap:hover {
background: rgba(124, 108, 255, 0.06);
border-color: rgba(124, 108, 255, 0.2);
}
.if-edit-display,
.if-edit-input {
font:
600 14px/1.3 system-ui,
sans-serif;
color: #f0eeff;
flex: 1;
min-width: 0;
}
.if-edit-display {
outline: none;
}
.if-edit-input {
border: 0;
outline: none;
background: transparent;
padding: 0;
}
.if-edit-pencil {
font-size: 12px;
color: #7a7899;
opacity: 0;
transition: opacity 0.15s;
}
.if-edit-wrap:hover .if-edit-pencil {
opacity: 1;
}
.if-edit-wrap.is-editing {
background: #1a1a22;
border-color: #7c6cff;
border-style: solid;
}
.if-edit-wrap.is-editing .if-edit-pencil {
display: none;
} // Inline Edit — click to edit, Enter saves, Escape cancels, blur commits
document.querySelectorAll("[data-if-edit]").forEach(function (wrap) {
var display = wrap.querySelector(".if-edit-display");
var input = wrap.querySelector(".if-edit-input");
function enter() {
wrap.classList.add("is-editing");
display.hidden = true;
input.hidden = false;
input.value = display.textContent;
input.focus();
input.select();
}
function commit() {
var v = input.value.trim();
if (v) {
display.textContent = v;
wrap.dataset.value = v;
} else {
input.value = display.textContent;
}
exit();
}
function cancel() {
input.value = display.textContent;
exit();
}
function exit() {
wrap.classList.remove("is-editing");
input.hidden = true;
display.hidden = false;
}
display.addEventListener("click", enter);
display.addEventListener("keydown", function (e) {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
enter();
}
});
input.addEventListener("blur", commit);
input.addEventListener("keydown", function (e) {
if (e.key === "Enter") {
e.preventDefault();
commit();
}
if (e.key === "Escape") {
e.preventDefault();
cancel();
}
});
});