Components
Components help you organize blocks of markup into files that can be referenced throughout your project with simple, declarative syntax.
Usage
To create a Component, add an HTML file in components
:
<div>
<yield />
</div>
The <yield />
tag will be replaced with the content passed to the Component:
<x-alert>
This text will replace the `yield` tag in the Component.
</x-alert>
Result:
<div>
This text will replace the `yield` tag in the Component.
</div>
Includes
You can safely omit the <yield />
tag if you want to use Components as includes, and don't actually need to pass any content to them:
<div>
This is a Component used as an include.
</div>
<x-alert />
Result:
<div>
This is a Component used as an include.
</div>
Tags
There are two ways to use Components:
- through the x-tag syntax
- through the
<component>
tag
x-tag
Component names are automatically registered and can be used without having to specify their file path, by using a Blade-like syntax: start with the string x-
followed by the kebab-case
name of the component file.
For example, let's use the alert.html
Component we created earlier:
<x-alert>
This text will replace the <yield /> tag in the Component.
</x-alert>
The following naming convention is used:
Component file | x-tag syntax |
---|---|
alert.html | <x-alert> |
alert_info.html | <x-alert_info> |
AlertInfo.html | <x-alertinfo> |
As you can see, the second and last examples are not very readable, which is why we recommend using a nested file structure instead.
<component> tag
Alternatively, you may use the <component>
tag to insert a Component:
<component src="components/alert.html">
This text will replace the <yield /> tag in the Component.
</component>
The src
attribute is mandatory and it needs to point to the Component's file path, relative to the project root.
If you're used to partials that you simply include in your HTML, this may look more familiar.
src
attribute is reserved on Components, make sure not to use it as a
prop
name.
Nested file structure
If a Component is nested deeper within your components
directory, you can reference it through dot notation.
For example, consider the following Component:
<a href="https://maizzle.com">
<yield />
</a>
You may reference it like this:
<x-button.alt>
Go to website
</x-button.alt>
The nested folder path comes after x-
, and the file name comes after the dot.
Index files
If you add an index.html
Component inside a nested directory, you can also reference it without its file name part:
<a href="https://maizzle.com">
<yield />
</a>
Both of these will work and use the same button/index.html
Component:
<x-button>
Go to website
</x-button>
<x-button.index>
Go to website
</x-button.index>
Slots
A Component may define slots, which act as placeholders that can be replaced (filled) with code when you use it.
For example, let's create a banner Component with a slot for a custom title:
<div role="banner">
<slot:title />
<yield />
</div>
We can use it like this:
<x-banner>
<fill:title>
<h2>This is the title</h2>
</fill:title>
<p>This is the content</p>
</x-banner>
The result will be:
<div role="banner">
<h2>This is the title</h2>
<p>This is the content</p>
</div>
Default content
A slot may have default content, which will be used if it hasn't been filled.
<div role="banner">
<h2>
<slot:title>Default title</slot:title>
</h2>
<yield />
</div>
Prepend
You may prepend content to a slot by using the prepend
attribute on the <fill>
tag.
<x-banner>
<fill:title prepend>Hello, </fill:title>
<p>This is the content</p>
</x-banner>
With our default slot:title
example, that would result in:
<div role="banner">
<h2>Hello, Default title</h2>
<p>This is the content</p>
</div>
Append
You may also append content to a slot by using the append
attribute on the <fill>
tag.
<x-banner>
<fill:title append>, what a name!</fill:title>
<p>This is the content</p>
</x-banner>
With our default slot:title
example, that would result in:
<div role="banner">
<h2>Default title, what a name!</h2>
<p>This is the content</p>
</div>
Check if a slot is filled
You may check if a slot has been filled by using the $slots
variable in a Component.
For example, let's create a <x-footer>
Component that will pull in another Component based on whether a copyright
slot has been filled or not:
<div>
<yield />
<if condition="$slots.copyright?.filled">
<!-- components/copyright.html -->
<x-copyright />
</if>
</div>
Stacks
You may push content to named stacks that can be rendered in other Components. This concept is similar to Blade's stack
and push
directives, also known as teleporting in frameworks like Vue.js.
For example, imagine you're coding a Shopify email template and need to add some Liquid code at the very top of the HTML, before the doctype
.
You would modify your Layout to include a stack
tag:
<stack name="liquid-vars" />
<!doctype html>
<html>
<head>
<style>
@tailwind components;
@tailwind utilities;
</style>
</head>
<body>
<yield />
</body>
stack
and
push
tags require a non-empty
name
attribute.
You may then push content to that stack from a Template:
<push name="liquid-vars">
{% capture email_title %} Your shopping cart is waiting for you {% endcapture %}
</push>
<x-layout>
<!-- your email HTML... -->
</x-layout>
Result:
{% capture email_title %} Your shopping cart is waiting for you {% endcapture %}
<!doctype html>
<!-- etc. -->
once
You may use the once
attribute on the <push>
tag to only push content once in a rendering cycle. This is useful if you're rendering the Component in a loop and want to make sure the contents of <push>
is only rendered once.
For example, imagine this Card Component:
<push name="head" once>
<style>
.card {
@apply bg-white rounded-lg shadow-md;
}
</style>
</push>
<div class="card">
<!-- ... -->
</div>
Looping over this Component will only push that CSS once to the head
stack:
<x-layout>
<each loop="item in [1,2,3]">
<x-card />
</each>
</x-layout>
Props
Props are attributes that can be added to a Component's tag. They can be used to pass data to the Component, or to configure its behavior.
To use props in a Component, you need to define them first. This is done by adding a <script>
tag with the props
attribute:
<script props>
module.exports = {
title: props.title || 'Default title'
}
</script>
<div>
{{ title }}
</div>
module.exports
is currently supported in Components.
Props that you pass to the Component will be available in the <script>
tag as the props
object. In this example we're getting the title
prop from props.title
, falling back to a default value if it's not provided.
The script uses module.exports
to export an object with props as keys. You can use these keys inside the Component through the curly braces syntax, as shown above.
To pass the title
prop to the Component, you would use the title
attribute:
<x-alert title="Hello, world!" />
Reserved props
The src
prop is reserved when used on Components - it will always try to load a Component file at the path defined in the attribute value.
So if you're trying to pass a src
prop to a Component, you should use a different name:
<script props>
module.exports = {
imgSrc: props['img-src'] || 'example.jpg',
}
</script>
<img src="{{ imgSrc }}">
<x-alert src="image.jpg" />
<x-alert img-src="image.jpg" />
Alternatively, you may change the prop attribute name to something other than src
:
export default {
components: {
attribute: 'href',
},
}
Encoding props data
When passing a props object to a Component, you need to encode the values.
For example, these won't work:
<x-alert props='{ "title": "Component's Title" }' />
<x-alert props='{ "title": "Component\'s Title" }' />
But this will:
<x-alert props='{ "title": "Component's Title" }' />
Aware props
By default, props are scoped to the Component and are not available to nested Components. If you need to change this, you may use the aware:
prefix when passing props to a Component:
Consider the following two Components:
<script props>
module.exports = {
title: props.title || 'Default child title'
}
</script>
<div>
Title in child: {{ title }}
</div>
<script props>
module.exports = {
title: props.title || 'Default parent title'
}
</script>
<div>
Title in parent: {{ title }}
<x-child />
</div>
If you pass the title
to the x-parent
Component:
<x-parent title="Hello, world!" />
... the result will be:
<div>
Title in parent: Hello, world!
<div>
Title in child: Default child title
</div>
</div>
As you can see, the title
prop was not passed down to the x-child
Component, and it used the default value instead.
To make sure a prop is passed down to all nested Components, use the aware:
prefix:
<x-parent aware:title="Hello, world!" />
Now you'll see the result that you'd expect:
<div>
Title in parent: Hello, world!
<div>
Title in child: Hello, world!
</div>
</div>
Attributes
You may pass HTML attributes to a Component and they will be added to the root element of the Component.
If you want to change the element to which the attributes are added, you can use the attributes
attribute:
<table>
<tr>
<td attributes>
<yield />
</td>
</tr>
</table>
Expressions in attributes
Expressions may be used in a Component's attribute:
---
title: "Hello, world!"
---
<x-alert title="{{ page.title }}" />
Attribute removal
The following attributes will be removed from the target element:
- unknown HTML attributes (see valid-attributes.js)
- attributes that are defined as props in the Component
Attribute merging
class
and style
attribute values will be merged with existing ones from the target element. All other attributes will be overwritten.
Safelist attributes
If you need to safelist or even block certain HTML attributes that you pass to a Component, see the Component configuration docs.
Variables
When creating a Component, you have access to global page
variables:
<div>
Building for: {{ page.env }}
</div>
Using this <x-example />
Component in a Template will render:
<div>
Building for: production
</div>