In Laravel Blade, what is the difference between a class-based component and an anonymous component, and when would you choose each?
answer
- class plus view, or view alone
- app/View/Components vs resources/views/components
- constructor props vs @props
- make:component, --view for anonymous
- class earns its keep with logic or DI
basics
~20 sA class-based component pairs a PHP class in app/View/Components with a view and takes props through its constructor; an anonymous component is just a Blade file in resources/views/components using @props. Pick a class for logic or injected services.
solid answer
~40 s`php artisan make:component Alert` creates `app/View/Components/Alert.php` and `resources/views/components/alert.blade.php`; the class's constructor parameters are its props, public properties and methods become template variables, dependencies can be injected, and `shouldRender()` can suppress it. `php artisan make:component alert --view` creates only the Blade file; that **anonymous** component declares props and defaults with `@props` and has no PHP class. Both are rendered as `<x-alert>`, both get `$attributes` and `$slot`, and neither sees the parent view's variables. Use an anonymous component for presentational pieces such as an alert box; use a class when the component computes things, needs a service from the container, or should hide itself conditionally, like a modal that loads room availability.
code
php · 26 lines<?php
namespace App\View\Components;
use App\Services\RoomAvailability;
use Illuminate\View\Component;
use Illuminate\View\View;
class AvailabilityModal extends Component
{
public function __construct(
public RoomAvailability $availability,
public string $checkIn,
public string $checkOut,
) {}
public function freeRooms(): array
{
return $this->availability->between($this->checkIn, $this->checkOut);
}
public function render(): View
{
return view('components.availability-modal');
}
}go deeper
Recall the two kinds, where their files live, make:component with --view, and that both render with an x- tag.
Explain constructor props versus @props, kebab-to-camel mapping, public methods as variables, and that components are isolated from parent variables.
Decide when logic, injected services or shouldRender justify a class, and guard runtime component selection with an allow-list.
Set a component-library convention - anonymous by default, classes for behaviour - so a growing UI stays consistent and reviewable.
## What a Blade component is A **Blade component** is a reusable piece of UI rendered with an HTML-like tag: `<x-alert type="warning">Room 204 is overbooked</x-alert>`. It receives **props** (declared inputs), an **attribute bag** of any extra HTML attributes, and **slots** of inner content. Unlike an `@include`, a component does **not** see the parent view's variables; everything it uses must be passed in or shared globally. Laravel offers two ways to define one. ## Class-based components ```bash php artisan make:component Alert ``` creates two files: - `app/View/Components/Alert.php` - a class extending `Illuminate\View\Component`. - `resources/views/components/alert.blade.php` - its template, returned from `render()`. The class gives you: 1. **Constructor props.** `public function __construct(public string $type, public string $message)` - attribute `type="error"` maps to `$type`; kebab-case attributes map to camelCase parameters (`alert-type` to `$alertType`). 2. **Public properties and methods as template variables.** A public method `isSelected($option)` is callable in the view as `$isSelected($option)`. 3. **Dependency injection.** Services listed before the data parameters are resolved from the container. 4. **`shouldRender()`**, which can return `false` to render nothing - for instance, an alert that hides itself when there is no message. 5. **`$except`**, a protected array listing public members that should not become template variables. `--inline` puts the markup in `render()` as a string instead of a separate view file, and `--test`, `--pest` or `--phpunit` also generate a test. ## Anonymous components ```bash php artisan make:component alert --view ``` creates only `resources/views/components/alert.blade.php`. There is no class; the template declares its props: ```html @props(['type' => 'info', 'dismissible' => false]) <div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>{{ $slot }}</div> ``` Attributes named in `@props` become variables (with the array values as defaults); everything else stays in `$attributes`. Nested paths use dots (`<x-modal.footer>` for `components/modal/footer.blade.php`), and a directory can hold its own root template (`components/modal/modal.blade.php` or `index.blade.php`) rendered as `<x-modal>`. ## Where Blade finds components Components are discovered automatically: `<x-alert>` resolves to the class `App\View\Components\Alert` if it exists, otherwise to the view `resources/views/components/alert.blade.php`. Dots map to sub-directories on both sides (`<x-forms.input>`). Packages and modular apps can add more anonymous locations with `Blade::anonymousComponentPath($path, $prefix)` in a provider's `boot()`, rendered as `<x-prefix::panel>` when a prefix is given. Names such as `data`, `render`, `resolve`, `view`, `shouldRender` and `withAttributes` are reserved and cannot be public properties or methods on a component class. ## Comparing them | | Class-based | Anonymous | |---|---|---| | Files | class + view (or inline) | one Blade file | | Props declared in | constructor | `@props` | | Logic | methods, computed properties | only what fits in the template | | Container services | constructor injection | none | | Suppress rendering | `shouldRender()` | wrap the markup in `@if` | | Typical use | modals with data, form controls with rules | alerts, badges, cards, buttons | ## Choosing for a hotel-admin UI - The **alert** (success, warning, danger) is pure presentation: an anonymous component with `@props(['type' => 'info'])` is enough. - The **confirm modal** is mostly markup with slots: anonymous works too. - A **room-availability modal** that asks a booking service for free rooms and formats dates is a class component: the constructor injects the service, a public method formats dates, and the template stays readable. A useful rule: start anonymous; promote to a class when the template grows PHP logic, or the component needs the container. ## Picking a component at runtime When the component name is only known at runtime - an alert whose style comes from a notification record - `<x-dynamic-component :component="'alerts.'.$notice->level" class="mt-2" />` renders the named component and forwards the remaining attributes. Keep the name to a known list; letting request data choose a component name lets a visitor render any component. ## Component or include? Includes are still fine for fragments that deliberately share the parent's context. A component wins when the piece has a clear interface - declared props, caller-supplied classes merged into the root element, named content areas - because that interface is visible at the call site and enforced by the component itself.
- Can a Blade component read variables defined in the view that renders it?No. Unlike `@include`, a component renders with only its props, attribute bag, slots and globally shared view data. A variable in the parent must be passed explicitly, for example `:guest="$guest"`. That isolation is what makes a component's interface visible at the call site.
- When would shouldRender() be the right tool?When the component itself knows it has nothing to show - an alert with an empty message, a banner outside its date range. Returning `false` from `shouldRender()` makes the tag render nothing, so call sites need no surrounding `@if`. Anonymous components have no class, so they must wrap their markup in a conditional instead.
- Why keep the name passed to x-dynamic-component to a known list?`x-dynamic-component` renders whatever component name it is given. If that name comes from request data, a visitor can render any component the app has, including admin-only fragments. Map the incoming value to an allow-list of component names first.
saying these in an interview costs you the question
- Anonymous components cannot receive props
- Components inherit the parent view's variables like @include
- Every component needs a PHP class in app/View/Components
- Constructor parameters must be written in kebab-case
- Class components are always faster, so anonymous ones should be avoided