Skip to main content
Version: 2.x

Layout

A well-though, user-friendly layout is one of the most important aspect of a frontend application.

Whether we talk about classic top bar/sidebar navigation, peculiar layouts crafted around a specific need, or even no layout at all, micro-lc provides the flexibility to meet every requirement dynamically composing applications layout at runtime on the basis of a user-supplied configuration.

Mount point

To understand how layout works, it is important to talk about micro-lc mount point, the place in DOM on which micro-lc appends the dynamic content.

In its simplest (and default) form, micro-lc mount point is a <div> tag with id __micro_lc and a <style> tag applying some base styling. The resulting tree depends on whether Shadow DOM is enabled, but regardless both the tags are rendered in the default DOM.

<micro-lc>
#shadow-root (open)
<slot>
↪️ <style>
↪️ <div>
</slot>

<style>
div#__micro_lc {
width: 100%;
height: 100%;
}

div#__micro_lc > :first-child {
width: inherit;
height: inherit;
overflow: hidden
}

div#__micro_lc > :first-child > div.composer-body {
width: inherit;
height: inherit;
overflow: hidden
}
</style>

<div id="__micro_lc">
<!-- Here micro-lc will mount the dynamic content -->
</div>
</micro-lc>

The <div> is always rendered, since micro-lc needs it to ensure content is correctly mounted. However, the <div> id can be changed, and the preset style can be disabled.

Any application or page mounted here is recommended to have its highest HTML element equipped with a css that allows its own internal scrolling. A good fit could be, for parcel applications,

.micro-lc-parcel-body {
height: inherit;
width: inherit;
overflow: auto;
}

Composition

micro-lc mount point can be personalized with the configuration key mountPoint, which accepts a content definition.

type MountPoint = string | number | Component | (Component | number | string)[]

The rationale behind a mount point personalization depends on Shadow DOM status:

  • if Shadow DOM is enabled, mount point allows to extend the layout with a portion outside Shadow DOM;
  • if Shadow DOM is disabled, mount point is actually the only way to define a layout, since layout key is not considered.

In a customized mount point, the actual element in which micro-lc should append the content likely needs to change. To instruct micro-lc of the new mount point, use the configuration key mountPointSelector, which accepts a valid query selector to be run on micro-lc base <div> (i.e., the one with id __micro_lc by default) subtree to find the new mount point.

caution

Any content of the node referenced by mountPointSelector will be substituted by micro-lc content.

caution

If mountPointSelector does not find a valid node, the whole mount point customization will be discarded and micro-lc will revert to its default settings.

Example with Shadow DOM
micro-lc.config.yaml
settings:
mountPoint:
tag: div
content:
- This is some addition to the layout outside micro-lc shadow-root
- tag: div
attributes:
id: custom_mount_point

mountPointSelector: "#custom_mount_point"

layout:
content:
tag: div
content:
- This is the layout
- tag: slot
Example without Shadow DOM
micro-lc.config.yaml
settings:
mountPoint:
tag: div
content:
- This is both layout and mount point, all outside micro-lc shadow-root
- tag: div
attributes:
id: custom_mount_point

mountPointSelector: "#custom_mount_point"

Build a layout

If micro-lc Shadow DOM is enabled, a custom layout can be built using the configuration key layout.

interface Layout {
sources?:
| string
| string[]
| {
uris: string | string[]
importmap?: ImportMap
}
content: Content
}

Through this structure, micro-lc is provided with a blueprint to follow to construct the desired DOM tree dynamically at runtime. The building blocks (content) are HTML5 elements or custom web components.

tip

Take a look at micro-lc add-on components for ready-to-use layout solutions.

The layout interface (and the engine behind its creation) has the same shape of the interface used to build composable applications. Hence, refer to that section for a detailed description of the subject.

Slotting

When building custom layouts, slots can be used to mark placeholders to be filled with markup at runtime.

A micro-lc layout needs one unnamed <slot> (i.e., a <slot> without the name attribute) to correctly mount the dynamic content.

micro-lc.config.yaml
layout:
content:
- tag: div
attributes:
class: top-bar
- tag: div
attributes:
class: main-content
content:
- tag: div
attributes:
class: side-bar
- tag: slot
tip

While micro-lc requires an unnamed <slot>, you can use as many named slots as you want to allow external injection of content in specific spots of the layout.

Two-level slotting

If you build a custom web component to be used as layout, and you want it to be in Shadow DOM too, you will face the issue of mounting the content through two levels of shadow-root.

To make this work, you need to append a <slot> as sibling of the layout web component Shadow DOM with the same name of the inner content <slot> so that any sibling of the layout is correctly mounted.

my-awesome-component.js
class MyAwesomeWebComponent extends HTMLElement {
constructor() {
super()

this._shadowRoot = this.attachShadow({ mode: 'open' })

this._container = this.ownerDocument.createElement('div')
this._container.appendChild(this.ownerDocument.createElement('slot'))
this._shadowRoot.appendChild(this._container)

this.appendChild(this.ownerDocument.createElement('slot'))
}
}

customElements.define('my-awesome-component', MyAwesomeWebComponent)