Components and UI kits

v0.0.1

A component is a reusable piece of markup that your pages draw by name, such as an alert, a card or a pricing table. A UI kit is a bundle of components with the JS hooks and the stylesheet they need, installed together. This page explains what a component is, who can draw it, how the CMS draws it, and how a kit brings a whole set of them to a site. To install a kit, follow Install or upgrade a UI kit.

What a component is

A component is a record in the database. It holds a template and a description of the values it takes. The visual editor lists the components of your site on the Components tab, and a page draws one with a component tag that names it and the site it comes from:

heex
<.component component_name="chelekom-alert" site="Global" />

The CMS compiles each component into a module, as it does for a page. See How a page reaches visitors. Because a component is a record, you can edit it in the builder, keep its history and restore an earlier copy.

The parts of a component

FieldWhat it holds
Name and DescriptionA name of 3 to 100 characters, unique within a site, and an optional description of up to 500.
Template and FormatThe markup, written as HEEx, EEx or Markdown. The default is HEEx.
TypeA category label of up to 50 characters, such as general, forms, navigations, overlays, feedback or media.
AttributesThe values the component takes. Each has a name and a type: string, integer, float, boolean, atom, list, map, any, global or struct.
SlotsThe areas where a page puts its own content inside the component.
Helper FunctionsSmall functions that the template calls.
Live componentOff, the component is a function component: it draws what it is given and holds nothing. On, it keeps its own state between renders and answers its own events, as a Phoenix LiveComponent.
PrecompileOn, the CMS builds the module at boot. Off, the first render that uses it builds it. It has no effect on the CSS.
dependenciesThe components and JS files this component needs, such as chelekom-icon.
requiredWhether the CMS cannot run without this component. The installer does not let you deselect it.
SiteThe site the component belongs to. Empty means global.

Global and site components

A component with no site is global. Every site can draw it, and the tag names it with site="Global". A component that has a site belongs to that site, and only that site can draw it. In the palette, a G badge marks a global component and a T badge marks one that only this site has.

A page draws the global components and the components of its own site, and nothing else. A tag that names a component of another site is refused before anything is built, and the page draws nothing in its place. A plugin can answer the runtime:render:component_unavailable event to draw markup of its own.

When a master installs from the Studio, This site adds the component to the site in the editor and All sites shares it with every site. A site admin installs to their own site.

How a component is drawn

  • The module. The CMS builds it at boot when Precompile is on, and otherwise on the first render that needs it. A page or layout builds the components it reaches, several at once, before it draws them.
  • The styles. The stylesheet of a site covers the components that the site reaches. A component that is not precompiled still renders styled the first time it appears.
  • The canvas. The editor draws a component in its cold state, with no process behind it, so a live component does not answer clicks there. The editor says so beside the selection.
  • Stored content. A post body or a documentation note can name a component with a marker that an author writes. If that component raises while it draws, the rest of the page still draws, and a small box that reads This component could not be drawn takes its place. The error is logged under an id, and only dashboard admins see the id. A live component is not caught this way.

UI kits

A UI kit is a mishka.ui_kit.bundle.v3 JSON file. Each entry under components is one component record, each entry under js_hooks is one JS hook and each entry under stylesheets is one stylesheet. The file is the install plan.

Kits come from three places:

  • The official kits. Chelekom ships a styled and a headless package. The installer fetches the newest release by default, and you can choose a pre-release or the master branch.
  • A file on the server. A bundle in the priv/cms_ui_kits/ folder is offered by the installer.
  • An extension. Mishka Blog and Mishka Document ship their components as a bundle, which installs when you set the extension up on a site.

What an install does

  1. It fires the runtime:ui_kit:before_install event.
  2. It checks each component against the kit contract. A component with no name or template, or with a field of the wrong shape, is skipped and named in the log. The rest of the kit installs.
  3. It writes every component, JS hook and stylesheet in one transaction, so an install that fails leaves nothing half written. A component that is archived on the site is skipped.
  4. It rebuilds the runtime once, after the whole kit has committed, and fires the runtime:ui_kit:after_install event.

A kit installs for every site or for one. A narrowed install, with chosen components and chosen variants or colors, renders without the values it leaves out. Components are named after their kit, as in chelekom-alert, so two kits installed side by side never replace each other's components. Removing a kit deletes the components with its prefix, and its JS hooks and stylesheets.

Updating a kit

The installer stamps each component with the version of the kit that wrote it and a fingerprint of what it wrote. An update, offered for the kits that extensions ship, compares those with the bundle. It updates a component that still equals what the kit installed. It writes a component someone edited only when an admin asks for it by name, and the copy it held stays in the history of the component.

Example: one global component and one of your own

You install Chelekom for every site. Your site, coffee-shop, also gets a component of its own named coffee-shop-promo. A page of that site draws both:

heex
<.component component_name="chelekom-alert" site="Global" />
<.component component_name="coffee-shop-promo" site="coffee-shop" />

The first tag draws on every site that has the kit. The second draws on coffee-shop only. A page of another site that names coffee-shop-promo draws nothing in its place. Attributes that a component requires go on the tag as well.