Rich Editor
A native word-processor editor with real A4 sheets, auto page flow, tables, ruler, headers/footers, image uploads, and optional Paperdoc export — no third-party editor bundles.
Basic Usage
One tag gives you the full chrome: menubar, toolbar, ruler, pages and status bar.
Content flows across printable sheets — typing past the bottom creates a new page; deleting pulls text back up.
Insert table
Or pick a size
×
Page setup
<neura::editor document-title="Quarterly report" />
<neura::editor
wire:model="content"
page-size="letter"
orientation="portrait"
:zoom="100"
:menubar="true"
:toolbar="true"
:ruler="true"
:statusbar="true"
/>
<neura::editor :paginated="false" />
Press
Ctrl+P
to print one sheet per page with chrome hidden.
Chrome Options
Strip the UI down for embedded forms or previews.
Insert table
Or pick a size
×
Page setup
<neura::editor
:menubar="false"
:ruler="false"
:statusbar="false"
placeholder="Toolbar only…"
/>
Tables
Insert → Table (or the toolbar table control) opens a dialog: type rows/columns, or hover the grid to pick a size.
Inside a table, right-click a cell for insert/delete row & column, or toggle the header row.
Tab
walks cells and adds a row at the end.
Page Setup
Sheet size and orientation come from config by default. Override per instance —
File → Page setup also changes them at runtime (zoom stays in the status bar).
<neura::editor page-size="a4" orientation="portrait" :zoom="100" />
<neura::editor page-size="letter" orientation="landscape" />
<neura::editor page-size="legal" />
Ruler, Headers & Footers
The ruler above the page is marked in inches. Drag the up-pointing markers for left/right margins,
and the down-pointing marker for first-line indent of the paragraph at the caret.
Double-click the top or bottom margin of the first page to edit the header or footer
(one of each, repeated on every sheet). Escape or click the body to exit.
Insert → Field drops page number, page count, document title or today’s date.
Dynamic fields use
data-nk-field
:
page
,
pages
,
title
,
date
.
<neura::editor
document-title="Quarterly report"
header='<span data-nk-field="title"></span>'
footer='Page <span data-nk-field="page"></span> of <span data-nk-field="pages"></span>'
/>
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Ctrl+B / I / U | Bold / italic / underline |
| Ctrl+K | Insert / edit link |
| Ctrl+Alt+0…4 | Paragraph / heading 1–4 |
| Ctrl+Shift+7 / 8 | Ordered / unordered list |
| Tab / Shift+Tab | Indent / outdent (or next/prev cell in tables) |
| Ctrl+Enter | Page break |
| Ctrl+Z / Y | Undo / redo (also Ctrl+Shift+Z) |
| Ctrl+\ | Clear formatting |
| Ctrl+P | |
| Escape | Close dialogs / exit header-footer |
Markdown-style markers at the start of a block, then Space:
#
–####
(headings),
-
/ *
/ +
(bullet list),
1.
(numbered list),
>
(blockquote).
On Mac, use ⌘ in place of Ctrl.
Livewire Integration
Bind with
wire:model
(debounced). Both HTML and JSON modes sync in real time.
<neura::editor wire:model="content" />
Form Integration
With a
name
attribute, a hidden input submits like any other field.
Description
Insert table
Or pick a size
×
Page setup
Provide a detailed description of the product.
<form method="POST" action="/posts">
<input type="hidden" name="_token" value="NMfZARN4b91Lli1T3QbmDS7jG34ROKGeLYLF02Iy" autocomplete="off">
<neura::field>
<neura::label>Description</neura::label>
<neura::editor name="description" placeholder="Enter product description…" />
<neura::description>
Provide a detailed description of the product.
</neura::description>
</neura::field>
<neura::button type="submit">Submit</neura::button>
</form>
Output Modes
Default output is clean HTML: page wrappers stripped, split paragraphs re-joined.
Use
mode="json"
for a structured document tree.
HTML Mode
Outputs clean HTML that can be rendered directly in your views.
Insert table
Or pick a size
×
Page setup
JSON Mode
Outputs a structured document tree, useful for processing or transforming content.
Insert table
Or pick a size
×
Page setup
<neura::editor mode="html" wire:model="content" />
<neura::editor mode="json" wire:model="content" />
Image Upload
Toolbar image button or drag-and-drop posts to the kit upload endpoint
(
neura-kit.editor.upload-image
)
or your upload-url
.
On failure the image embeds as a data URL and
editor-upload-failed
is dispatched.
<neura::editor
wire:model="content"
upload-url="{{ route('my.custom.upload') }}"
upload-field="image"
/>
Configuration: Configure image storage in
config/neura-kit.php or via environment variables:
NEURA_KIT_EDITOR_IMAGE_DISK (s3, local, etc.) and
NEURA_KIT_EDITOR_IMAGE_PATH (storage path).
Export & Import (Paperdoc)
Optional. With
paperdoc-dev/paperdoc-lib
installed,
File gains Open… and Download. Export uses the current page size,
orientation and margins. Import is sanitized through the editor schema before load.
Menu entries hide when the package is missing.
composer require paperdoc-dev/paperdoc-lib
Disabled State
Disable the editor to make it read-only. The toolbar is automatically hidden when disabled;
pagination still applies so the document reads as in print.
Insert table
Or pick a size
×
Page setup
<neura::editor disabled wire:model="content" />
Events
Events bubble from the editor root. Listen with Alpine or Livewire:
| Event | Detail |
|---|---|
| input | Serialized value (HTML or JSON, depending on mode) |
| title-change | New document title string |
| header-footer-change | { header, footer }
after leaving header/footer edit |
| editor-upload-failed | { file, reason }
— image falls back to a data URL |
<div
x-on:title-change="console.log($event.detail)"
x-on:header-footer-change="console.log($event.detail)"
x-on:editor-upload-failed="toast($event.detail.reason)"
>
<neura::editor wire:model="content" />
</div>
Configuration
Configure default editor settings in
config/neura-kit.php or via environment variables.
// config/neura-kit.php
'editor' => [
'page_size' => env('NEURA_KIT_EDITOR_PAGE_SIZE', 'a4'),
'orientation' => env('NEURA_KIT_EDITOR_ORIENTATION', 'portrait'),
'max_image_size' => env('NEURA_KIT_EDITOR_MAX_IMAGE_SIZE', 10240), // KB
'image_disk' => env('NEURA_KIT_EDITOR_IMAGE_DISK', 'public'),
'image_path' => env('NEURA_KIT_EDITOR_IMAGE_PATH', 'editor/images'),
// Requires paperdoc-dev/paperdoc-lib
'export_formats' => ['pdf', 'docx', 'html', 'md'],
'import_formats' => ['docx', 'html', 'md', 'txt', 'csv', 'pdf'],
'max_export_bytes' => 5_242_880,
'max_import_kilobytes' => 20_480,
],
// .env
NEURA_KIT_EDITOR_PAGE_SIZE=a4
NEURA_KIT_EDITOR_MAX_IMAGE_SIZE=10240
NEURA_KIT_EDITOR_IMAGE_DISK=s3
NEURA_KIT_EDITOR_IMAGE_PATH=editor/images
Props
| Property | Type | Default | Description |
|---|---|---|---|
| name | string | null | Hidden input name for form submit |
| value | string|array | null | Initial HTML (or JSON tree) |
| mode | string | html | html · json
|
| placeholder | string | Start writing… | Empty-document hint |
| disabled | boolean | false | Read-only; hides toolbar |
| debounce | number | 300 | ms before syncing wire:model / state |
| document-title | string | Untitled document | Menubar title (editable) |
| page-size | string | config | a4 · letter · legal
|
| orientation | string | config | portrait · landscape
|
| zoom | number | 100 | Initial zoom % |
| paginated | boolean | true | Sheet flow vs continuous |
| header / footer | string | null | Initial header/footer HTML |
| menubar | boolean | true | Title + File/Edit/View/Insert/Format |
| toolbar | boolean | true | Formatting toolbar |
| ruler | boolean | true | Margin / indent ruler |
| statusbar | boolean | true | Page / words / zoom |
| upload-url | string | auto | Custom image upload endpoint |
| upload-field | string | image | Multipart field name |
Best Practices
Security
Input is schema-sanitized (no scripts / event handlers /
javascript:
URLs), but always sanitize again on the server before storing —
submitted HTML can still be tampered with in transit.
Image Storage
Use S3 (or similar) in production. Without a reachable upload endpoint,
images fall back to data URLs and inflate stored HTML.
Performance
No third-party editor bundle. Raise
debounce
for very long documents, or set :paginated="false"
when page geometry does not matter.