Hello,
Blade passes PHP expressions to components through :-prefixed attributes, and the Laravel docs prescribe kebab-case for multi-word names (Passing Data to Components, "Casing": "kebab-case should be used when referencing the argument names in your HTML attributes").
PHP Tools only treats the value of such an attribute as PHP when the attribute name consists of letters only:
:labelPrefix="…" and :foobar="…" get hover and completion.
:label-prefix="…", :label_prefix="…" and :foo2="…" get neither: no hover, and completion returns no items.
The short attribute syntax :$date, documented as equivalent to :date="$date", isn't analysed either. It also switches off analysis of the bound attribute that immediately follows it, even across a line break. Any other attribute in between restores it.
Environment
- PHP Tools for VS Code 1.75.19379 (linux-x64)
- VS Code 1.142.0
- Laravel 13.35.0 (anonymous components with
@props)
Steps to reproduce
{{-- resources/views/components/item.blade.php --}}
@props(['date' => null, 'labelPrefix' => null])
<span>{{ $labelPrefix }}</span>
@php($date = now())
<x-item :label-prefix="$date->format('Y')" /> {{-- ✗ no hover on $date, no completion after -> --}}
<x-item :labelPrefix="$date->format('Y')" /> {{-- ✓ --}}
<x-item label-prefix="{{ $date->format('Y') }}" /> {{-- ✓ but not equivalent, see below --}}
<x-item :$date /> {{-- ✗ no hover on $date --}}
<x-item :$date :labelPrefix="$date->format('Y')" /> {{-- ✗ the following attribute is lost too --}}
<x-item :$date class="x" :labelPrefix="$date->format('Y')" /> {{-- ✓ analysed again --}}
Expected
- The value of every
:-prefixed attribute on an <x-…> tag is analysed as PHP, whatever its name. Blade itself accepts [\w\-:.@]+ as a bound attribute name (ComponentTagCompiler::parseBindAttributes()).
:$name is treated like :name="$name". Blade rewrites it textually (ComponentTagCompiler::parseShortAttributeSyntax()), without affecting the attributes around it.
- Unchanged:
::-prefixed attributes ("Escaping Attribute Rendering" on the same page) and : attributes on plain HTML elements are not PHP.
Why it matters
kebab-case is the documented spelling. It is also the only multi-word spelling that the official Laravel extension's grammar highlights as PHP ((:[a-z-]+)(=)(")), so today users must choose between syntax highlighting and IntelliSense.
The workaround label-prefix="{{ … }}" keeps both but is not equivalent. Blade passes the value through e(), so it arrives as an escaped string: null becomes '', and objects or arrays throw a TypeError.