Skip to content

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.