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>
Discard default content
Sometimes you may need to discard the content of a slot that has default content. You can do this by using an empty <fill> tag.
Consider the following component:
<div>
<slot:title>
<h2>
Default title
</h2>
</slot:title>
<yield />
</div>
If you need to use this component in a context where the title doesn't make sense, an empty <fill> tag will will simply set the content to nothing:
<x-banner>
<fill:title />
<p>This is the content</p>
</x-banner>
This will effectively render an empty slot:title, resulting in:
<div>
<p>This is the content</p>
</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>