In a Blade view, what do @class, @style, @checked and @selected compile to, and what hand-written template code do they replace?
answer
- conditional attributes without inline ifs
- @class writes the whole class attribute
- array key is class, value is condition
- @checked echoes checked when true
- values are not HTML-escaped
basics
~20 s@class and @style take an array of always-on entries plus entry => condition pairs and write a complete class or style attribute; @checked, @selected, @disabled, @readonly and @required print the bare attribute when their condition is true.
solid answer
~30 s`@class(['card', 'card--current' => $plan->is($current), 'opacity-50' => ! $plan->available])` compiles to `class="<?php echo Arr::toCssClasses(...) ?>"`: numeric keys always apply, string keys apply when their value is truthy, joined with spaces. It writes the whole attribute, so you never write `class="@class(...)"`. `@style` does the same through `Arr::toCssStyles`, adding a trailing `;` to each entry. `@checked($cond)` compiles to `if ($cond) echo 'checked'`, and `@selected`, `@disabled`, `@readonly` and `@required` follow the same pattern. They replace inline `@if`/ternaries inside tags. One caution: the class and style strings are not HTML-escaped, so keep keys literal rather than built from user input.
code
html · 20 lines<div @class([
'plan-card',
'plan-card--current' => $plan->is($currentPlan),
'opacity-50' => ! $plan->available,
])>
<h3>{{ $plan->name }}</h3>
</div>
<label>
<input type="checkbox" name="annual" value="1" @checked(old('annual', $isAnnual))>
Bill annually
</label>
<select name="plan">
@foreach ($plans as $plan)
<option value="{{ $plan->slug }}" @selected(old('plan', $currentPlan->slug) === $plan->slug)>
{{ $plan->name }}
</option>
@endforeach
</select>go deeper
Recall that @class takes always-on and conditional entries and writes the whole attribute, and @checked or @selected print the attribute when true.
Explain the compiled output through Arr::toCssClasses and Arr::toCssStyles, and how old() with @checked repopulates forms after validation.
Spot the unescaped output when class or style values come from user data, and move variant logic into components or PHP.
Agree on where presentation logic lives: literal utility classes in directives, variants in components, rules in PHP, so templates stay readable and safe.
## The problem they solve Conditional attributes written by hand clutter a tag and invite spacing and quoting bugs: ```html <div class="card {{ $plan->is($current) ? 'card--current' : '' }} {{ $plan->available ? '' : 'opacity-50' }}"> <option value="pro" {{ $selected === 'pro' ? 'selected' : '' }}>Pro</option> ``` Blade provides directives that turn these into data. ## @class and @style `@class` takes an array. Entries with a **numeric key** are always included; entries with a **string key** are included when their value is truthy: ```html <div @class([ 'card', 'card--current' => $plan->is($currentPlan), 'opacity-50' => ! $plan->available, ])> ``` Compiled, it becomes `class="<?php echo \Illuminate\Support\Arr::toCssClasses([...]); ?>"`. Points worth knowing: - The directive emits the **entire `class="..."` attribute**. Writing `class="@class(...)"` produces a nested, broken attribute. - An array entry may hold several classes in one key (`'border ring-2' => $featured`). - With no argument, it produces an empty `class=""`. `@style` works the same way through `Arr::toCssStyles`, which appends `;` to each entry that lacks one: `@style(['color: gray', 'font-weight: bold' => $featured])` yields `style="color: gray; font-weight: bold;"`. ## @checked, @selected and friends These print a **boolean attribute** - an HTML attribute whose presence alone means true: | Directive | Compiled PHP | Typical use | |---|---|---| | `@checked($c)` | `if ($c): echo 'checked'; endif;` | checkboxes, radios | | `@selected($c)` | `... echo 'selected' ...` | `<option>` | | `@disabled($c)` | `... echo 'disabled' ...` | buttons, inputs | | `@readonly($c)` | `... echo 'readonly' ...` | inputs | | `@required($c)` | `... echo 'required' ...` | inputs | Combined with the `old()` helper, they re-populate a form after a failed submit: `@checked(old('annual', $subscription->annual))` ticks the box from the last submission, falling back to the stored value. ## A pricing table example A plan picker page shows cards and a billing form: 1. Each card uses `@class` to highlight the visitor's current plan and dim unavailable plans. 2. The "annual billing" checkbox uses `@checked(old('annual', $isAnnual))`. 3. The plan `<select>` marks the current plan with `@selected(old('plan', $current->slug) === $plan->slug)`. 4. The submit button uses `@disabled(! $user?->canUpgrade())` for visitors who cannot change plans. ## The escaping caution `Arr::toCssClasses` and `Arr::toCssStyles` **join strings; they do not HTML-escape them**, and the compiled directive echoes the result without `e()`. With literal keys that is harmless. If a class name or style value is built from user data - a "theme" field, a colour from a profile - a double quote in that data can close the attribute and inject new ones. Keep keys literal, map user choices to an allow-list (`'theme-'.$allowedTheme`), or cast numbers before interpolating. `@checked` and its siblings print fixed words, so their risk is only in the condition, not the output. ## Reading the compiled output Looking at the compiled view in `storage/framework/views` makes the behaviour obvious. `@class([...])` becomes a literal `class="` followed by a PHP echo of `Arr::toCssClasses(...)` and a closing quote; `@checked($x)` becomes `<?php if($x): echo 'checked'; endif; ?>`. There is no escaping step and no attribute merging: the directives are thin, predictable shortcuts, which is why they are easy to review and why their inputs must be literal or allow-listed. ## When not to use them - A single static class needs no directive. - Complex, reusable variant logic (size, tone, state) belongs in a component, where the attribute bag can merge classes passed by the caller; that is component material. - Business rules - who may upgrade, which plan is available - belong in PHP; the directive should receive a boolean, not compute one from several models.
- What goes wrong with class="base @class(['active' => $on])"?`@class` emits a complete `class="..."` attribute, so the output is a class attribute containing another class attribute, which browsers misparse. Put every class in the array instead: `@class(['base', 'active' => $on])`.
- Why is @class(['theme-'.$user->theme => true]) risky?The directive joins the keys with spaces and echoes them without HTML escaping. A theme value containing a double quote can close the class attribute and add attributes such as an event handler. Map the stored value to an allow-list of known themes before it reaches the view.
saying these in an interview costs you the question
- @class goes inside an existing class="" attribute
- @class escapes class names like {{ }} does
- @checked prints checked="false" when the condition is false
- @style requires each entry to end with a semicolon
- These directives are only usable inside components