AST

Components and Slots

Blade components (<x-alert>) are parsed as ComponentNode instances. Forte supports Blade, Livewire, and Flux component prefixes out of the box, and allows registering custom prefixes.

#Component Basics

ComponentNode extends ElementNode, so all element methods (attributes, children, tag name, etc.) are available on components.

You can inspect a component's identity with getComponentName (name without prefix), getPrefix (the prefix itself), and getType (the component type):

1<?php
2
3use Forte\Ast\Components\ComponentNode;
4use Forte\Facades\Forte;
5
6$doc = Forte::parse('<x-alert type="warning">Watch out!</x-alert>');
7
8$component = $doc->findComponentByName('x-alert');
9
10$component->getComponentName(); // "alert"
11$component->getPrefix(); // "x-"
12$component->getType(); // "blade"
13$component->tagNameText(); // "x-alert"

For nested components using dot notation, getNameParts splits the name into an array:

1<?php
2
3$doc = Forte::parse('<x-admin.card.header />');
4
5$component = $doc->findComponentByName('x-admin.card.header');
6
7$component->getNameParts(); // ["admin", "card", "header"]

#Component Types and Prefixes

Forte registers three component prefixes by default:

Prefix Type Example
x- blade <x-alert>
livewire: livewire <livewire:counter>
flux: flux <flux:button>

You can identify the framework a component belongs to with getType:

1<?php
2
3$doc = Forte::parse('<livewire:counter />');
4
5$component = $doc->findComponentByName('livewire:counter');
6
7$component->getType(); // "livewire"
8$component->getPrefix(); // "livewire:"

#Registering Custom Components

If your project uses a custom component prefix, register it with ComponentManager before parsing:

1<?php
2
3use Forte\Components\ComponentManager;
4use Forte\Facades\Forte;
5use Forte\Parser\ParserOptions;
6
7$manager = new ComponentManager();
8$manager->register('my-');
9
10$options = ParserOptions::defaults()->components($manager);
11$doc = Forte::parse('<my-widget title="Hello" />', $options);
12
13$component = $doc->findComponentByName('my-widget');
14
15$component->getComponentName(); // "widget"
16$component->getPrefix(); // "my-"
17$component->getType(); // "my"

You can list all registered prefixes:

1<?php
2
3$manager->getPrefixes(); // ["x-", "livewire:", "flux:", "my-"]

To check whether a tag name matches any registered prefix:

1<?php
2
3$manager->isComponent('my-widget'); // true
4$manager->isComponent('div'); // false

For detailed component metadata without parsing a full template, use parseComponentName:

1<?php
2
3$meta = $manager->parseComponentName('x-admin.card');
4
5$meta->type; // "blade"
6$meta->prefix; // "x-"
7$meta->componentName; // "admin.card"
8$meta->nameParts; // ["admin", "card"]
9$meta->isSlot; // false

#Slots

Components may contain named slots that organize content into distinct sections.

You can check for slot presence with hasSlots (any slots) or hasSlot (a specific named slot):

1<?php
2
3$doc = Forte::parse('
4<x-card>
5 <x-slot:header>Card Title</x-slot:header>
6 Card body content
7 <x-slot:footer>Card Footer</x-slot:footer>
8</x-card>
9');
10
11$card = $doc->findComponentByName('x-card');
12
13$card->hasSlots(); // true
14$card->hasSlot('header'); // true
15$card->hasSlot('sidebar'); // false

To retrieve a specific slot by name:

1<?php
2
3$header = $card->slot('header'); // ?SlotNode
4$footer = $card->slot('footer'); // ?SlotNode

You can also retrieve all slots at once, or filter to only named slots:

1<?php
2
3$card->getSlots(); // array<SlotNode>
4$card->getNamedSlots(); // array<SlotNode>

#Default Slot Content

Content that is not inside a named slot is considered the default slot. Check for its presence with hasDefaultSlot:

1<?php
2
3$card->hasDefaultSlot(); // true

To access the default slot content, use getDefaultSlot for the raw child nodes or defaultSlotContent for the rendered string:

1<?php
2
3$card->getDefaultSlot(); // array<Node> (non-slot children)
4$card->defaultSlotContent(); // string (rendered content)

For a collection-based API, defaultSlotChildren returns the default slot as a NodeCollection:

1<?php
2
3$card->defaultSlotChildren(); // NodeCollection

#Finding Slots by Base Name

When a component uses multiple slots with the same base name (e.g., collection slots), you can retrieve them together:

1<?php
2
3$card->getSlotsNamed('header'); // array<SlotNode>
4$card->hasMultipleSlotsNamed('header'); // bool

#Dynamic Slots

Forte supports "dynamic slot" syntax, which is not available in Laravel core. You can detect dynamic slots with isDynamic and retrieve the expression with dynamicExpression:

1<?php
2
3use Forte\Ast\Components\SlotNode;
4use Forte\Facades\Forte;
5
6$doc = Forte::parse('
7<x-card>
8 <x-slot:[$name]>Dynamic content</x-slot>
9</x-card>
10');
11
12$card = $doc->findComponentByName('x-card');
13$slot = $card->getSlots()[0];
14
15$slot->isDynamic(); // true
16$slot->dynamicExpression(); // "$name"
17$slot->baseSlotName(); // "$name"
18$slot->isMultiValue(); // false

For static slots, isDynamic returns false and dynamicExpression returns null:

1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('
6<x-card>
7 <x-slot:header>Title</x-slot:header>
8</x-card>
9');
10
11$card = $doc->findComponentByName('x-card');
12$slot = $card->slot('header');
13
14$slot->isDynamic(); // false
15$slot->dynamicExpression(); // null
16$slot->baseSlotName(); // "header"

#Variadic Slots

Like with dynamic slot syntax, Forte supports variadic (multi-value) slots using bracket syntax ([]) to indicate they accept multiple values. Detect them with isMultiValue and get the base name with baseSlotName:

1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('
6<x-list>
7 <x-slot:items[]>First</x-slot>
8 <x-slot:items[]>Second</x-slot>
9 <x-slot:items[]>Third</x-slot>
10</x-list>
11');
12
13$list = $doc->findComponentByName('x-list');
14
15$list->getSlotsNamed('items'); // array<SlotNode> (3 slots)
16$list->hasMultipleSlotsNamed('items'); // true

Each individual variadic slot reports its multi-value status and base name:

1<?php
2
3$slots = $list->getSlotsNamed('items');
4
5$slots[0]->isMultiValue(); // true
6$slots[0]->baseSlotName(); // "items"
7$slots[0]->isDynamic(); // false

#Generic Type Arguments

The genericTypeArguments method is inherited from ElementNode and works on any element. Use genericTypeArguments to retrieve the type parameter string:

1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<x-data-table<App\Models\User> />');
6
7$component = $doc->findComponentByName('x-data-table');
8
9$component->genericTypeArguments(); // "<App\Models\User>"

When no generic type is present, the method returns null:

1<?php
2
3use Forte\Facades\Forte;
4
5$doc = Forte::parse('<x-alert />');
6
7$component = $doc->findComponentByName('x-alert');
8
9$component->genericTypeArguments(); // null

#Additional Properties

For convenience, ComponentNode exposes additional magic properties as shorthand for common method calls:

1<?php
2
3$component->componentName; // string (same as getComponentName())
4$component->slotName; // ?string (same as getSlotName())
5$component->slots; // LazyCollection<SlotNode>
6$component->namedSlots; // LazyCollection<SlotNode>
7$component->defaultSlot; // LazyCollection<Node>

You can also check whether a component is itself a slot definition (e.g., <x-slot:header>) and retrieve its name:

1<?php
2
3$component->isSlot(); // bool
4$component->getSlotName(); // ?string

#Finding Components

You can locate components by tag name (including prefix) using dedicated finder methods. The singular variant returns the first match, while the plural variant returns a LazyCollection:

1<?php
2
3$doc->findComponentByName('x-alert'); // ?ComponentNode
4$doc->findComponentsByName('x-alert'); // LazyCollection<ComponentNode>

To traverse all components in the document tree:

1<?php
2
3$doc->components; // LazyCollection of all ComponentNode instances

You may filter and inspect the collection:

1<?php
2
3// Find all Livewire components
4$livewire = $doc->components->filter(fn($c) => $c->getType() === 'livewire');
5
6// Find components with slots
7$withSlots = $doc->components->filter(fn($c) => $c->hasSlots());
8
9// Get all component names
10$names = $doc->components->map(fn($c) => $c->getComponentName())->unique()->all();

#See also

  • Elements: HTML element nodes that ComponentNode extends
  • Directives: Blade directive nodes
  • Traversal: Navigate and query the document tree