Skip to main content

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);
note

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.

note

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);
note

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:

MyButton.jsx
class MyButton extends LeafComponent {
render() {
return <button>My button</button>;
}
}

registerComponent('my-button', MyButton);

export default MyButton;
MyOtherComponent.jsx
import MyButton from './MyButton.jsx';

// ...

class MyOtherComponent extends LeafComponent {
render() {
return (
<MyButton />
);
}
}

// ...

In the resulting HTML template, MyOtherComponent will be converted to:

index.html
<!-- ... -->

<!-- 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.

MyButton.jsx
class MyButton extends LeafComponent {
render() {
return (
<button>
<slot />
</button>
);
}
}
App.jsx
class MyApp extends LeafComponent {
render() {
return <MyButton>Hello MyButton</MyButton>;
}
}

The above example will show a button with text Hello MyButton inside.

caution

Although the usage of JSX makes Leaf very similar to React, but Leaf doesn't provide a this.props.children wrapper!