Components
Components let you package markup into reusable building blocks with clear inputs and clean output. Think of them as small, composable templates that keep your views tidy without hiding the PHP you still need.
INFO
Components are template files resolved from a configurable components path and rendered with props and slots.
Basic Component Usage
Component (components/s-button.sugar.php):
<button class="btn" type="button">
<?= $slot ?>
</button>Usage:
<s-button>Click Me</s-button>TIP
Component tags use the s- prefix, and component filenames should include the same prefix (for example, components/s-button.sugar.php).
INFO
If you change the prefix to x-, the filename becomes components/x-button.sugar.php and the tag becomes <x-button>.
Component Filename Pattern
Component files must use the element prefix and end with .sugar.php:
{prefix}-{name}.sugar.phpExamples:
s-button.sugar.php-><s-button>s-user-card.sugar.php-><s-user-card>x-alert.sugar.php-><x-alert>when the prefix isx-
INFO
The fragment element filename (for example, s-template.sugar.php, x-template.sugar.php, or your configured fragment name) is reserved and not treated as a component.
Components in the Templates Tree
This is the typical place components live. The highlighted lines show the component directory and files.
templates/
├── pages/
│ ├── home.sugar.php
│ └── profile.sugar.php
├── layouts/
│ └── base.sugar.php
├── partials/
│ ├── header.sugar.php
│ └── footer.sugar.php
└── components/
├── s-button.sugar.php
├── s-card.sugar.php
└── s-alert.sugar.php Props and Defaults
Components receive props as variables. Define defaults at the top of the component:
<?php
$title ??= 'Untitled';
$elevated ??= false;
?>
<article class="card" s:class="['card--elevated' => $elevated]">
<h3><?= $title ?></h3>
<?= $slot ?>
</article><s-card s:bind="['title' => 'Profile', 'elevated' => true]">
<p>Profile content here</p>
</s-card>Dynamic Component Invocation (s:component)
<div s:component="button">Click Me</div><div s:component="$componentName">Click Me</div><s-template s:component="alert" s:bind="['type' => 'info']">Hello</s-template>Component Props with s:bind
<s-alert s:bind="['class' => 'alert alert-success', 'title' => 'Well done!']">
Your changes have been saved.
</s-alert><s-alert s:bind="$alertProps">Your changes have been saved.</s-alert>WARNING
Only props passed through s:bind become component variables. Regular attributes are merged onto the root element.
Attribute Merging
Attributes not consumed as props are merged onto the component root element:
<s-card class="shadow-lg" id="profile-card" @click="handleClick" x-data="{ open: false }">
Profile content here
</s-card>Named Slots
<s-card>
<h3 s:slot="header">User Profile</h3>
<s-template s:slot="footer">
<button>Cancel</button>
<button>Save</button>
</s-template>
<p>Main content here</p>
</s-card><article class="card">
<header><?= $header ?? '' ?></header>
<section><?= $slot ?></section>
<footer><?= $footer ?? '' ?></footer>
</article>TIP
Named slots are available as $header, $footer, or any s:slot name you provide.
Slot Fallbacks
<article class="card">
<header><?= $header ?? '<h3>Default header</h3>' ?></header>
<section><?= $slot ?></section>
</article>Best Practices
- Use
s:bindfor component props, not HTML attributes. - Keep a single root element in component templates.
- Output slot variables directly:
<?= $slot ?>. - Provide fallbacks for optional slots.