Get Started › Inline Editor
Instead of replacing a <textarea> with a boxed editor, inline mode turns
content you already have on the page — a <div>, an <article>,
any element — into the editable surface itself, in place. No menu bar, no fixed toolbar, no status
bar. It's the mode you want for CMS-style "click to edit this section" pages.
Unlike the boxed themes, inline mode doesn't start from a hidden <textarea>
— the element's existing HTML is the initial content. Give it a hook to select on:
<div data-inline>
<h2>Welcome</h2>
<p>This paragraph is a live inline editor.</p>
</div>
Any element works — <div>, <article>, <section> — as long as it's not a <textarea>, which can only ever hold plain text.
inline: true
Same AlpineEditor.init() call as any other mode, just with inline: true and selector pointing at the element(s) from step 1:
document.addEventListener('alpine-editor:ready', () => {
AlpineEditor.init({
selector: '[data-inline]',
inline: true,
});
});
alpine-editor:ready before calling init() — see Get started. theme and height are ignored when inline is set.There's no chrome to click into — the element itself responds to hover and focus:
| State | What happens |
|---|---|
| Hover | A light outline previews that the element is editable. |
| Focus (click in) | The outline turns solid and a floating toolbar appears, left-aligned to the element — above it by default, or below if there isn't room above. |
| Blur (click away) | The outline and toolbar disappear. Clicking into a toolbar control (e.g. a color picker) doesn't count as blurring. |
Everything else — typing, undo/redo (Ctrl/Cmd+Z), links (Ctrl/Cmd+K), find & replace (Ctrl/Cmd+F), tables — works exactly like the boxed themes. The one exception is fullscreen: there's no container to expand, so Ctrl/Cmd+Shift+F has no effect in inline mode.
selector can match more than one element — each becomes its own independent inline editor instance, exactly like a CMS wiring up several separately editable regions on one page:
<div class="page">
<div data-inline><h2>Welcome</h2><p>First block.</p></div>
<div data-inline><p>A second, independent block.</p></div>
</div>
<script>
AlpineEditor.init({ selector: '[data-inline]', inline: true }).then((editors) => {
console.log(editors.length); // 2
});
</script>
With no menu bar to fall back on, inline mode's default toolbar is a richer, two-row set that covers fonts and colors directly:
// inline mode's default toolbar — two rows
[
'undo redo | bold italic underline | fontfamily fontsize',
'forecolor backcolor | alignleft aligncenter alignright | bullist numlist | outdent indent',
]
Override it the same way as any theme, with a single string or an array of strings for multiple rows — see the full token reference in Themes & Toolbar.
AlpineEditor.init({
selector: '[data-inline]',
inline: true,
toolbar: 'bold italic | link',
});
getContent(), setContent() and onChange all work exactly like the boxed themes — full reference in Content & Events. The one difference: a boxed editor mirrors its content back onto a hidden <textarea>.value on every change; inline mode skips that step, since the element you selected already is the content.
const [editor] = await AlpineEditor.init({ selector: '[data-inline]', inline: true });
document.getElementById('save').addEventListener('click', () => {
fetch('/api/sections/1', {
method: 'PUT',
body: JSON.stringify({ html: editor.getContent() }),
});
});
editor.destroy() removes the floating toolbar and turns off contentEditable — unlike the boxed themes, the element isn't hidden or replaced, its current content just stays on the page, no longer editable:
editor.destroy();
destroy() just to stop being counted against your usage.<div class="page">
<div data-inline>
<h2>Welcome</h2>
<p>Hover this block to see it's editable, click in for the toolbar.</p>
</div>
</div>
<script src="https://your-app.test/embed/YOUR_TOKEN.js"></script>
<script>
document.addEventListener('alpine-editor:ready', () => {
AlpineEditor.init({
selector: '[data-inline]',
inline: true,
onChange: (editor) => console.log(editor.getContent()),
});
});
</script>