Maizzle v4.4.0-beta.1
This release adds Laravel Blade-like components to Maizzle.
We're currently testing this in beta, so if you want to try it out in an existing project do a clean install of Maizzle from the next
tag:
-
delete your
node_modules
andpackage-lock.json
-
update
package.json
:- "@maizzle/framework": "latest", + "@maizzle/framework": "next",
-
run
npm install
For new projects, scaffold using the next
branch of the official Starter:
npx degit maizzle/maizzle#next my-project
Configuration
Components are still configured via your build.components
config key.
Until we get a proper guide to configuring the new components, please have a look at the posthtml-component
options.
For reference, these are the defaults that Maizzle uses:
{
root: build.components.root || './',
folders: ['src/components', 'src/layouts', 'src/templates'],
tag: 'component',
attribute: 'src',
yield: 'content',
propsAttribute: 'locals',
}
Using the new syntax
The syntax is similar to Laravel Blade, where the component tag name is based on the component's file name or path (dot syntax).
By default, Maizzle is configured to look for components in the following folders in your project:
- src/components
- src/layouts
- src/templates
This makes it easy to use the new components even for layouts.
For a basic example, create src/components/sample.html
:
Hello, <content></content>
You can use it like this:
<x-sample>world!</x-sample>
Result:
Hello, world!
Nested path syntax
You may reference components inside a folder like in Blade, through dot notation.
Let's say you have the following components:
src/components/footer/index.html
src/components/footer/legal.html
You can use dot notation like so:
<x-footer:index>Footer</x-footer:index>
<!-- you can also omit the `:index` part if the file is index.html -->
<x-footer>Footer</x-footer>
<x-footer:legal>Legal Footer</x-footer:legal>
Slots
You may define slots and fill them with content like so:
<slot:header></slot:header>
Hello, <content></content>
You can use it like this:
<x-sample>
<fill:header>
👋
</fill:header>
world!
</x-sample>
Result:
👋
Hello, world!
This means you can replace the old way of extending layouts and only use components everywhere:
src/layouts/main.html
:
- <block name="template></block>
+ <fill:template></fill:template>
src/templates/example.html
:
- <extends src="src/layouts/main.html">
- <block name="template></block>
- </extends>
+ <x-main>
+ <fill:template></fill:template>
+ </x-main>
Stacks
You may push content to named stacks and render them in a different place:
<!-- src/layouts/main.html -->
<html>
<head>
<stack name="head"></stack>
</head>
<body>
<fill:template></fill:template>
</body>
</html>
Then, in a component:
<!-- src/components/sample.html -->
<push name="head">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400&&family=Raleway:wght@400&display=swap" rel="stylesheet" media="screen">
</push>
The contents of the <push>
tag will replace <stack name="head">
.
Props
You can pass props to a component through attributes.
Define the props that the component accepts in a <script props>
tag like so:
<!-- src/components/sample.html -->
<script props>
module.exports = {
text: props.text || 'Default text'
}
</script>
<div>
{{ text }}
</div>
You can then pass the prop to the component:
<x-sample text="Hello world!"></x-sample>
Result:
<div>
Hello world!
</div>
Important: if you don't setup the props that the component accepts, any attributes you add to the component will also be added to the first HTML node inside it. This is how frontend frameworks work too.
Passing locals
If you need to pass a JSON string, use the locals
attribute (configurable):
<x-sample locals='{"text": "Hello world"}'></x-sample>
Make sure that the value is a valid JSON string.
Component nesting and aware
props
Similar to Laravel Blade, props passed to a parent component will not be available by default to any child components.
To achieve this, pass the prop by prefixing it with the aware:
keyword.
Consider these parent/child components:
<!-- src/components/parent.html -->
<script props>
module.exports = {
text: props.text || 'Default text'
}
</script>
<div>
Prop in parent: {{ text }}
<x-child></x-child>
</div>
<!-- src/components/child.html -->
<script props>
module.exports = {
text: props.text|| 'Default text'
}
</script>
<div>
Prop in child: {{ text }}
</div>
To make text
available to <x-child>
, you'd pass it like so:
<x-parent aware:text="Hello world!"></x-parent>
Attributes
Any attributes that you pass to a component will be added to the first node:
<!-- src/components/sample.html -->
<div class="font-bold">
<content></content>
</div>
<x-sample class="text-base" data-id="1">Test</x-sample>
Result:
<div class="font-bold text-base" data-id="1">
Test
</div>
class
and style
attributes will be merged with existing ones, unles you override them with the override:
prefix:
<x-sample override:class="text-base" data-id="1">Test</x-sample>
Result:
<div class="text-base" data-id="1">
Test
</div>
You may also change the root element that attributes are added to in a component, through the attributes
attribute:
<!-- src/components/sample.html -->
<main class="font-bold">
<div attributes>
<content></content>
</div>
</main>
<x-sample data-id="1">Test</x-sample>
Result:
<main class="font-bold">
<div data-id="1">
Test
</div>
</main>
Backwards compatibility
The new components system is backwards-compatible with the previous one, so you can still write components as:
<component src="src/components/example.html">
This text will replace the `<content>` tag in the Component.
</component>
Components as layouts
Components can now also be used as a replacement for the existing layout/template templating relationship.
The old <extends>
/ <block>
syntax can still be used, but will very likely be removed in Maizzle 5.