Laravel Blade-inspired components for PostHTML with slots, attributes as props, custom tags and more.
npm install posthtml-component[npm]: https://www.npmjs.com/package/posthtml-component
[npm-version-shield]: https://img.shields.io/npm/v/posthtml-component.svg
[npm-stats]: http://npm-stat.com/charts.html?package=posthtml-component
[npm-stats-shield]: https://img.shields.io/npm/dt/posthtml-component.svg
[github-ci]: https://github.com/posthtml/posthtml-components/actions/workflows/build.yml
[github-ci-shield]: https://github.com/posthtml/posthtml-components/actions/workflows/build.yml/badge.svg
[license]: ./LICENSE
[license-shield]: https://img.shields.io/npm/l/posthtml-component.svg
Laravel Blade-inspired components for PostHTML
[![Version][npm-version-shield]][npm]
[![Build][github-ci-shield]][github-ci]
[![License][license-shield]][license]
[![Downloads][npm-stats-shield]][npm-stats]
``bash`
npm i -D posthtml-component
This PostHTML plugin provides an HTML-friendly syntax for using components in your HTML templates.
If you are familiar with Blade, React, Vue or similar, you will find the syntax to be familiar, as this plugin is inspired by them.
See also the first PostHTML Bootstrap UI using this plugin and check also the starter template here.
| Name | Type | Default | Description |
|--------------------------|--------------------|----------------------------------------------|----------------------------------------------------------------------------------|
| root | String | './' | Root path where to look for components. |String[]
| folders | | [''] | Array of paths relative to options.root or defined namespaces. |String\|String[]
| fileExtension | | 'html' | Component file extensions to look for. |String
| tagPrefix | | 'x-' | Tag prefix. |String\|Boolean
| tag | | false | Component tag. Use with options.attribute. Boolean only false. |String
| attribute | | 'src' | Attribute to use for defining path to component file. |String[]
| namespaces | | [] | Array of namespace root paths, fallback paths, and custom override paths. |String
| namespaceSeparator | | '::' | Namespace separator for tag names. |String
| yield | | 'yield' | Tag name for injecting main component content. |String
| slot | | 'slot' | Tag name for slots |String
| fill | | 'fill' | Tag name for filling slots. |String
| slotSeparator | | ':' | Name separator for and tags. |String
| stack | | 'stack' | Tag name for . |String
| push | | 'push' | Tag name for . |String
| propsScriptAttribute | | 'props' | Attribute in
`
The output will be:
`html`
Header content
Body content
The once attribute allows you to push content only once per rendering cycle.
For example, if you are rendering a given component within a loop, you may wish to only push the JavaScript and CSS the first time the component is rendered.
Example.
`html
`
By default, the content is pushed in the stack in the given order. If you would like to prepend content onto the beginning of a stack, you may use the prepend attribute:
`html
`
props can be passed to components in HTML attributes. To use them in a component, they must be defined in the component's
Use:
`html
`The output will be:
`html
Hello world!
`If no
title attribute is passed to the component, the default value will be used.`html
`The output will be:
`html
Default title
`Inside
Use:
`html
size="xl"
title="My modal title"
items='["third", "fourth"]'
class="modal-custom"
/>
`The output will be:
`html
My modal title
first
second
third
fourth
`Notice how the
class attribute that we passed to the component is merged with class attribute value of the first node inside of it.You can change how attributes are merged with global props defined via options, by passing a callback function.
By default, all props are scoped to the component, and are not available to nested components. You can however change this accordingly to your need.
Create a component:
`html
Prop in child: {{ title }}
`Create a
component that uses :`html
Prop in parent: {{ title }}
`Use it:
`html
`The output will be:
`html
Prop in parent: My title
Prop in child: Default title
`As you can see,
title in component renders the default value and not the one set via . To change this, we must prepend
aware: to the attribute name in order to pass the props to nested components.`html
`The output now will be:
`html
Prop in parent: My title
Prop in child: My title
`$3
You can pass any attributes to your components and they will be added to the first node of your component,
or to the node with an attribute named
attributes. If you are familiar with Vue.js, this is the same as so-called
fallthrough attribute. Or, with Laravel Blade, it's
component-attributes.
By default,
class and style are merged with existing class and style attribute. All other attributes are overridden by default.If you pass an attribute that is defined as a
prop, it will not be added to the component's node.Here's an example:
`html
`Use the component:
`html
`Result:
`html
`If you need to override
class and style attribute values (instead of merging them), just prepend override: to the attribute name:`html
`Result:
`html
`If you want the attributes to be passed to a certain node, use the
attributes attribute:`html
Hello world!
`Use the component:
`html
`Result:
`html
Hello world!
`You can add custom rules to define how attributes are parsed - we use posthtml-attrs-parser to handle them.
$3
If default configurations for valid attributes are not right for you, you may configure them as explained below.
`js
// index.js
const { readFileSync, writeFileSync } = require('fs')const posthtml = require('posthtml')
const components = require('posthtml-component')
const options = {
root: './src',
// Add attributes to specific tag or override defaults
elementAttributes: {
DIV: (defaultAttributes) => {
/ Add new one /
defaultAttributes.push('custom-attribute-name');
return defaultAttributes;
},
DIV: (defaultAttributes) => {
/ Override all /
defaultAttributes = ['custom-attribute-name', 'another-one'];
return defaultAttributes;
},
},
// Add attributes to all tags, use '*' as wildcard for attribute name that starts with
safelistAttributes: [
'custom-attribute-name',
'attribute-name-start-with-*'
],
// Remove attributes from all tags that support it
blocklistAttributes: [
'role'
]
}
posthtml(components(options))
.process(readFileSync('src/index.html', 'utf8'))
.then(result => writeFileSync('dist/index.html', result.html, 'utf8'))
`Examples
You can work with
and or you can create component for each block of your component, and you can also support both of them.You can find an example of this inside
docs-src/components/modal. Following is a short explanation of both approaches.$3
Let's suppose we want to create a component for bootstrap modal.
The code required is:
`html
`There is almost three block of code: the header, the body and the footer.
So we could create a component with three slots:
`diff
`We can then use it like this:
`html
id="exampleModal"
aria-labelledby="exampleModalLabel"
>
My modal
Modal body content goes here...
`$3
Another approach is to split the component in smaller components, passing attributes to each of them.
So we create a main component and then three different smaller components:
`html
``html
``html
``html
`And then you can use it like this:
`html
id="exampleModal"
aria-labelledby="exampleModalLabel"
>
My modal
Modal body content goes here...
`As said in this way you can pass attributes to each of them, without defining props.
$3
You can also combine both approaches, and then use them with slots or with small components:
`html
class="modal fade"
tabindex="-1"
aria-hidden="true"
aria-modal="true"
role="dialog"
>
Now you can use your component with slots or with small components.
As you may notice, by using slots, you already can use also your small components, and so you can also pass props
via
$slots which has all the props passed via slot, and as well check if slot is filled.Migration
If you are migrating from
posthtml-extend and/or posthtml-modules please to follow updates here:
posthtml-components/issues/16.Contributing
See PostHTML Guidelines and contribution guide.
Credits
Thanks to all PostHTML contributors and especially to
posthtml-extend and posthtml-modules` contributors, as part of code is ~~stolen~~ inspired from these plugins.