- Overview
- Usage
- ->language() — the visual badge
- ->tabSize() — tab-to-spaces behavior
- Visual behavior
- Why no CodeMirror?
- Example: snippet CMS
Overview
AuraCodeEditor extends Filament\Forms\Components\Textarea and dresses it up as a credible code input without bundling CodeMirror, Monaco, or any other editor library. You get a dark glass surface, a monospace font, a language badge pinned to the top-right, and proper tab behavior — all for about 1 KB of JS and a single stylesheet.
If you need full IDE-grade syntax highlighting, pair this field with your own CodeMirror/Monaco instance. For the 90% case — config snippets, JSON settings, example code, shell commands — AuraCodeEditor is drop-in ready.
Usage
use BlueStarSystem\AuraFilament\Forms\Components\AuraCodeEditor;
AuraCodeEditor::make('snippet')
->label('PHP snippet')
->language('php')
->tabSize(4)
->rows(12)
->helperText('Press Tab to insert 4 spaces. Shift+Tab outdents.');
->language() — the visual badge
AuraCodeEditor::make('snippet')->language('php'); // "PHP" badge
AuraCodeEditor::make('snippet')->language('json'); // "JSON"
AuraCodeEditor::make('snippet')->language('bash'); // "BASH"
AuraCodeEditor::make('snippet')->language(''); // no badge
AuraCodeEditor::make('snippet'); // no badge (default)
The language string is emitted as data-language on the root, and the stylesheet renders the badge with content: attr(data-language) inside a pinned ::after. It's purely visual — there's no server-side lexer, no file-extension mapping, nothing to install.
->tabSize() — tab-to-spaces behavior
AuraCodeEditor::make('snippet')->tabSize(2); // 2-space indent
AuraCodeEditor::make('snippet')->tabSize(4); // default
AuraCodeEditor::make('snippet')->tabSize(8); // upper clamp
The value is clamped to [1, 8]. A tiny inline Alpine handler intercepts Tab, inserts the configured number of spaces at the caret, and dispatches an input event so Livewire stays in sync.
Shift+Tab removes up to tabSize leading spaces from the current line — a sensible outdent.
No external JS is loaded; the handler is inlined into x-on:keydown.tab.prevent at render time.
Visual behavior
| State | What you see |
|---|---|
| Default | Dark glass (#0f172a), neutral border, monospace JetBrains Mono falling back to system mono |
| Focus | Primary border, primary glow at 0.2 alpha, soft outer shadow |
| Selection | Primary-tinted highlight at 0.35 alpha |
| Caret | --primary-400 — always matches the active theme |
| Placeholder | Muted low-alpha white |
| Language badge | Pinned top-right, primary pill with primary-300 text |
| Read-only / disabled | Card fades to 0.75 opacity, focus ring disappears |
The field is dark by design, but it lives comfortably in both light and dark page contexts — the only difference between the two is a slightly softer outer shadow in light mode.
Why no CodeMirror?
Every extra JS dependency shipped by Aura has to earn its place. Bundling CodeMirror 6 or Monaco would:
- Add ~200 KB to 4+ MB of gzipped JS to every panel that registers Aura.
- Require a matching webpack/vite configuration on the consumer's side.
- Collide with other parts of a project that already ship their own editor.
A styled textarea covers most real-world form use cases (snippet fields, JSON settings, shell commands, template bodies). For the rare case where a full editor is genuinely needed, developers typically already have one in the project and can wire it in via ->hint() or a custom Livewire component.
Example: snippet CMS
use BlueStarSystem\AuraFilament\Forms\Components\AuraCodeEditor;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Select;
use Filament\Schemas\Components\Section;
Section::make('Snippet')
->columns(2)
->components([
TextInput::make('title')->required(),
Select::make('language')
->options([
'php' => 'PHP',
'json' => 'JSON',
'js' => 'JavaScript',
'bash' => 'Bash',
'css' => 'CSS',
])
->required()
->reactive(),
AuraCodeEditor::make('body')
->label('Code')
->language(fn ($get) => $get('language'))
->tabSize(fn ($get) => $get('language') === 'json' ? 2 : 4)
->rows(14)
->columnSpanFull(),
]);
The language badge and tab size follow the selected language reactively. See it live on demo.aura-ui.com/admin/components-showcase.