Sheath rule
blade-no-directive-attribute-collision
@error="...", @empty="...") compile as the directive, not the listener.
#Why
Vue and Alpine spell event listeners @event="handler". Blade compiles
statements before the browser or either framework sees the template,
and it does not care that the @ sits inside a tag. When the event name is
also a Blade directive, Blade wins:
<img :src="src" @error="handleError">
compiles to
<img :src="src" <?php if($errors->has(...)): ?>="handleError">
The listener never binds, and the compiled tag is corrupted PHP-in-markup.
Any known directive name can collide this way: @error, @empty,
@selected, @checked, @disabled, @section, and so on.
Blade also consumes a known directive prefix before a kebab or colon suffix, so
@csrf-token="..." and @csrf:token="..." corrupt the compiled tag too.
Names Blade does not know (@click, @submit.prevent, @keydown.escape)
pass through untouched and are never reported. Blade directives used on
purpose in attribute position (@checked($value), @class([...])) take
arguments in parentheses, not ="...", and are never reported either.
#Examples
#Bad
<img :src="src" @error="handleError">
<div @empty="reload()">Refresh</div>
<x-alert @error="handleError" />
<div @csrf-token="refresh"></div>
#Good
<!-- Longhand listener syntax never collides -->
<img :src="src" x-on:error="handleError">
<img :src="src" v-on:error="handleError">
<!-- The escape hands the attribute to the browser as written -->
<img :src="src" @@error="handleError">
<div @@empty="reload()">Refresh</div>
<!-- Unknown event names pass through Blade untouched -->
<button @click="open = true">Open</button>
<form @submit.prevent="save">...</form>
<!-- Blade directives used on purpose in attribute position -->
<x-input @checked($isChecked) />
<div @class(['p-4', 'font-bold' => $active])>...</div>
#Notes
- The reported shape is a known directive name followed by an optional
modifier, kebab suffix, or colon suffix, then optional HTML whitespace and
=(for example@error.window = "..."and@csrf-token="..."). A bare@errorwith no=is not reported. - Checked on plain elements and component tags alike. Inside a component tag the same collision also stops the tag compiling as a component at all.
- No auto-fix is available because the intended framework syntax cannot be inferred.
#Related Rules
- blade-no-directive-space - directive arguments in component tags
- blade-valid-directive-arguments - directive collisions in prose, CSS, and JS