Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Blade Emerald Laravel Package

aqua/blade-emerald

aqua/blade-emerald is a Laravel package that provides reusable Emerald-styled Blade components for building clean, consistent interfaces. Install via Composer, publish assets, and compose buttons, forms, cards, and layouts with simple Blade tags.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require aqua/blade-emerald:^1.2

v1.2.0 is a compatibility release only — it adds declared support for Laravel 10 and PHP 8.2. There are no new directives, operators, or config keys, so anything written against v1.0/v1.1 continues to work. What changes is only your floor: if you are on PHP 8.2 and Laravel 10, this is the first version you should pin to.

Laravel's package auto-discovery should register the service provider; if not, add Aqua\BladeEmerald\BladeEmeraldServiceProvider::class to config/app.php. Check vendor/aqua/blade-emerald/config/ and publish if present:

php artisan vendor:publish --provider="Aqua\BladeEmerald\BladeEmeraldServiceProvider"

Before writing code, confirm the constraints resolve on your platform (composer why aqua/blade-emerald, or read vendor/aqua/blade-emerald/composer.json for the php and illuminate/* ranges). v1.2.0 explicitly names Laravel 10 and PHP 8.2; if you are on Laravel 11/12, verify what the constraint actually allows rather than assuming the range is open.

Where to look first

  1. README.md – confirm the exact directive/helper name and supported abbreviation syntax. The package is small (31 stars, no dependents), so verify the API against the source rather than assuming Emmet parity.
  2. src/ – the abbreviation parser is the core; read it to learn which Emmet operators are actually supported (child >, sibling +, class ., id #, multiplication *, attributes []).
  3. config/ – any defaults for wrapper tags, class prefixes, or component namespace. Nothing in v1.2.0 adds config keys, so a config you published on v1.1 is still current — diff it after upgrading anyway.

First use case

Generate a Blade component whose template is scaffolded from an Emmet-style abbreviation, then use it in a view:

php artisan make:emerald-component Card "div.card>h2.title+p.body"

Rendered inside a Blade view, the component emits the nested markup and exposes a default slot so you can inject content:

<x-card>
    Your body copy here
</x-card>

The value is not the one-off scaffolding — it is replacing hand-written nesting in the 20-line component templates you write every week so the HTML tree stays declarative and the class lists stay consistent.

Implementation Patterns

Inline wrapping in a view. The "wrap … with markup" framing implies a directive that takes a block and wraps it with the generated structure, roughly:

@emerald('section.hero>div.container')
    <h1>{{ $title }}</h1>
@endemerald

Use this for repeated structural shells (hero sections, card grids, modals) that you do not want to promote to full components.

Scaffold-then-edit workflow. Treat the command as a generator, not a runtime dependency:

  • Run the generator, commit the resulting .blade.php.
  • Never regenerate a component that has been hand-edited (or regenerate to a --force-safe temp path and diff).
  • Keep the abbreviation in a comment at the top of the generated file so reviewers know how it was produced.

This keeps the blast radius small if the package stops being maintained — the output is plain Blade you own.

Component-as-wrapper pattern. Generate a wrapper component once, then nest:

{{-- resources/views/components/layout/panel.blade.php --}}
<div {{ $attributes->class(['panel', 'panel--'.$variant]) }}>
    {{ $slot }}
</div>
<x-layout.panel variant="error">
    @emerald('ul.list>li.item') ... @endemerald
</x-layout.panel>

$attributes and $slot merge naturally because the package only emits markup; it does not fight Blade's component attribute bag.

Consistency across a design system. If the package exposes a config for class prefixes or a tag allowlist, put your design-token classes there (card, card__header) rather than spelling them inline in every abbreviation. One change in config propagates to all abbreviations — which is exactly the abstraction benefit you are paying for.

CLI batch generation. Drive it from a shell loop or a custom Artisan command for one-off migrations:

for spec in "Card:div.card>h3.card-title+p.card-body" "Badge:span.badge"; do ...
done

Useful when retrofitting a legacy view into components — you get consistent shells fast, then paste the existing content into the slots.

Testing integration. Assert on rendered output, not on the abbreviation:

$this->blade('<x-card>Hi</x-card>')
     ->assertSee('class="card"', false)
     ->assertSee('Hi');

Because the package compiles to Blade, assertSee(..., false) on the escaped HTML is the most stable contract.

Pin a CI matrix that matches the declared support. Since v1.2.0 exists specifically to declare Laravel 10 / PHP 8.2 compatibility, encode that in CI: one job on PHP 8.2 + Laravel 10 that renders a generated component. That is the cheapest guard against the next compatibility release being needed and not shipped.

Gotchas and Tips

  • v1.2.0 narrows the risk, but only for one stack. The release declares Laravel 10 and PHP 8.2 support; it says nothing about Laravel 11/12 or PHP 8.3+. Treat Laravel 10 + PHP 8.2 as the tested path and verify anything newer yourself. Pin the version in composer.json ("aqua/blade-emerald": "^1.2") and smoke-test one view after every Laravel upgrade. If it breaks at compile time, you can usually replace the directive with a static partial in minutes — the generated Blade is portable.
  • It is a compatibility bump, not a feature bump. Do not go looking for new operators or config keys. The Emmet coverage you read out of the parser on v1.1 is identical on v1.2.0. If you had a fork or a subclass to work around a missing operator, that workaround is still required.
  • Upgrade is low-risk but not zero-risk. The composer.json constraints changed, which can shift dependency resolution in a large app. Run composer update aqua/blade-emerald --with-dependencies --dry-run first and read the diff; then render one generated component and one inline @emerald block before merging.
  • Verify Emmet coverage. "Emmet-like" is not Emmet. Read the parser source to confirm which of >, +, ^, *, #, ., [], {} are supported. Text nodes ({...}) and grouping are the ones most often missing in small implementations.
  • Compile errors surface as Blade line numbers in the wrong place. When a directive mis-parses, the exception points at the compiled view in storage/framework/views, not your source. Inspect the compiled file to see what the parser produced — it is the fastest debug loop. Clear storage/framework/views after upgrading, since stale compiled views from the previous version mask (or fake) a compile problem.
  • Config caching. If you publish a config or class map, php artisan config:cache freezes it. During development, php artisan config:clear or run without caching; a common "it works in tinker but not in the browser" symptom is a stale config cache.
  • Escaping. Generated markup must be output raw ({!! !!} or via a directive that does not escape). Do not double-escape by wrapping the directive output in {{ }} — you will get literal &lt;div&gt;.
  • Attributes on components. If you use generated components with {{ $attributes }}, ensure the package does not emit its own class attribute that will collide. Prefer $attributes->class([...]) in the wrapper so consumer classes merge instead of overwrite.
  • Whitespace and line breaks. Naive emitters concatenate tags without newlines, producing unreadable HTML and breaking snapshot tests. Post-process or configure prettification if the package supports it.
  • Do not rely on it at runtime for user-facing feature code. Its value is authoring-time. If the directive appears inside every view, a future Laravel upgrade blocks your whole app; if it appears only at generation time, upgrades are trivial.
  • Extension points. If you need custom tags or class mapping and the config does not expose it, subclass the generator and bind your own instance in a service provider rather than editing vendor/. A single maintenance release after a long gap is not a maintenance commitment — if you need fixes upstream, fork and reference your fork via a VCS repository entry in composer.json.
  • Security. Abbreviations are developer-authored, but if you ever build one from user input, treat it as a template injection vector. Never interpolate request data into an abbreviation.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource