Components
Components are a core concept in Leafjs. This article will walk through those core concepts about Leafjs components.
Each Leaf component is a valid web-component, which is basicly a natively supported custom element.
Defining a component
Every Leafjs component should inherit from the LeafComponent
class. A basic component will be as follows:
import { LeafComponent, registerComponent } from '@leaf-web/core';
class MyComponent extends LeafComponent {
constructor() {
super();
}
render() {
return <h1>Component content</h1>;
}
}
registerComponent('my-component', MyComponent);
It is required that you call super()
inside the constructor of your component.
However, if you have nothing other than super()
in the constructor, you may omit declaring the constructor:
class MyComponent extends LeafComponent {
render() {
return <h1>Component content</h1>;
}
}
But whenever you declare the constructor, call super()
first!
Render functions
Render functions define how a component should be rendered on the DOM. Leafjs takes full advantage of JSX, which allows HTML-like syntax in JavaScript.
class MyComponent extends LeafComponent {
constructor() {
super();
}
render() {
return (
<div>
<h1>Hello Leafjs!</h1>
<p>Lorem ipsum dor sit.</p>
</div>
);
}
}
In JSX, you can also use JavaScript expressions in your template:
class MyComponent extends LeafComponent {
constructor() {
super();
}
render() {
const name = 'John Doe';
return (
<div>
<h1>Hello {name}!</h1>
<p>Lorem ipsum dor sit.</p>
</div>
);
}
}
This will render Hello John Doe!
on the screen.
JSX may seem like HTML, but it isn't. Under the hood, the above code is transpiled into:
class MyComponent extends LeafComponent {
constructor() {
super();
}
render() {
const name = 'John Doe';
/*
before transpilation:
return (
<div>
<h1>Hello {name}!</h1>
<p>Lorem ipsum dor sit.</p>
</div>
);
*/
// after transpilation:
return createElementReactStyle(
'div',
{},
createElementReactStyle('h1', {}, `Hello ${name}!`),
createElementReactStyle('p', {}, 'Lorem ipsum dor sit.')
);
}
}
Which is still valid JS code.
Registering a component
Each Leafjs component need to be registered before actual usage. To do that, Leaf provides a high level wrapper to register the custom components to the registery. See the example below.
import { LeafComponent, registerComponent } from '@leaf-web/core';
class SomeComponent extends LeafComponent {
// component content...
}
// register `SomeComponent` with name `component-name`
registerComponent('component-name', SomeComponent);
This allows the usage of component-name
element in HTML templates AND using document.createElement
. Under the hood, Leafjs calls the custom component registery as follows:
customElements.define(name, component);
The first parameter of registerComponent
, or the component name, needs to contain at least one hyphen. More information on custom element name rules here.
Using your component
After defining and registering your own custom Leaf component, you probably want to reuse it in other components. Although each component is a valid web-component, which means you can use it in your template directly using <component-name />
, this is NOT recommended.
For better consistency and code maintainability, you probably want to have jump-to-defination feature when using your own components. To do that, first export your component:
class MyButton extends LeafComponent {
render() {
return <button>My button</button>;
}
}
registerComponent('my-button', MyButton);
export default MyButton;
import MyButton from './MyButton.jsx';
// ...
class MyOtherComponent extends LeafComponent {
render() {
return (
<MyButton />
);
}
}
// ...
In the resulting HTML template, MyOtherComponent
will be converted to:
<!-- ... -->
<!-- MyOtherComponent inner HTML -->
<my-button></my-button>
<!-- ... -->
Children slots
If you want to render your component's children, for example a button with custom content, use the Web Components <slot />
element.
class MyButton extends LeafComponent {
render() {
return (
<button>
<slot />
</button>
);
}
}
class MyApp extends LeafComponent {
render() {
return <MyButton>Hello MyButton</MyButton>;
}
}
The above example will show a button with text Hello MyButton
inside.
Although the usage of JSX makes Leaf very similar to React, but Leaf doesn't provide a this.props.children
wrapper!