There may be times when you want to pass HTML attributes to your component, for example when you have an anchor component that takes care of ARIA attributes for you:
// a.blade.php
@php
$href = $attributes->get('href');
$role = $attributes->get('role');
$role = $role ?? (isset($href) ? null : 'link');
$ariaDisabled = $attributes->get('aria-disabled');
if (!isset($ariaDisabled)) {
$ariaDisabled = isset($href) ? null : 1;
if ($ariaDisabled === 1) {
$ariaDisabled = $role !== "button" ? "true" : null;
}
}
@endphp
<a {{ $attributes->merge([
'aria-disabled' => $ariaDisabled,
'role' => $role
])
}}>{{ $slot }}</a>
<!-- index.html -->
<nav>
<h2>My website</h2>
<ul>
<li><x-a class="link link--active">Home</x-a></li>
<li><x-a href="/dashboard" class="link">Dashboard</x-a></li>
</ul>
</nav>
Unpacking works on both HTML elements and Blade components, except when nesting in another class-based Blade component. There is no issue when unpacking is used inside anonymous components.
app\\
View\\
Components\\
A.php
Navbar.php
resources\\
view\\
components\\
a.blade.php
footer.blade.php
navbar.blade.php
Using <x-a class="link">
inside <x-footer>
will work without issues, while inside <x-navbar>
you would need to pass attributes as a property.
<!-- footer.blade.php -->
<x-a class="link">About us</x-a>
<!-- navbar.blade.php -->
<x-a :attributes="(new ComponentAttributeBag())->class([ 'link link--active' ])">Home</x-a>
What is the Issue Here?
I haven’t dug much into the internals of the Blade Compiler, but I think it has something to do with parsing raw strings. Here is an excerpt of vendor/laravel/framework/src/Illuminate/View/Compilers
:
// ...
protected function compileOpeningTags(string $value)
{
$pattern = "/
<
\s*
x[-\:]([\w\-\:\.]*)
(?<attributes>
(?:
\s+
(?:
(?:
@(?:class)(\( (?: (?>[^()]+) | (?-1) )* \))
)
|
(?:
@(?:style)(\( (?: (?>[^()]+) | (?-1) )* \))
)
|
(?:
\{\{\s*\\\$attributes(?:[^}]+?)?\s*\}\}
)
|
(?:
(\:\\\$)(\w+)
)
|
(?:
[\w\-:.@%]+
(
=
(?:
\\\"[^\\\"]*\\\"
|
\'[^\']*\'
|
[^\'\\\"=<>]+
)
)?
)
)
)*
\s*
)
(?<![\/=\-])
>
/x";
return preg_replace_callback($pattern, function (array $matches) {
$this->boundAttributes = [];
$attributes = $this->getAttributesFromAttributeString($matches['attributes']);
return $this->componentString($matches[1], $attributes);
}, $value);
}
// ...
There are 110 matches for attributes
in this file, and some more patterns like this one.
Will it be Fixed?
It hasn’t been fixed yet, and I don’t think it will, because there is a closed issue on Github with the solution of explicitly passing the attributes
property: https://github.com/laravel/framework/issues/47360