Component state: $

Each component gets a live state variable named $. This variable allows for fine-grained reactivity in a concise manner.

Note: Not yet comfortable with live variables? See live() first to learn more!

The live variable is used both for internal logic as well as exposing properties and methods on the custom element. It is available in a component's <script> section as well as inside inline expressions in component's <template>.

Syntax

$.property; $.method(); $.$attributes.name; $.$other.$custom.properties;

Details

The live component state variable $ is crucial in writing components with Yozo. It is created once for each component instance, giving authors full control over internal component state. Its reactivity powers properties, attributes, methods, and other logic, such as {{ inline }} expressions, #for loops and more. It is also the primary (and only) way to share data between a component's <script> and its <template>. The following properties on $ are automatically created or looked for:

Of course, other properties beyond these may be set (including binding data with live.link() at any point to retain any arbitrary live data and to share it with the <template>, where expressions always include $ into their scope.

Examples

Markdown editor

Let's say we have a function md.render() that takes a string of Markdown as input, and outputs HTML (as a string). We'll build a component that lets a used enter some Markdown-formatted text into a <textarea>, and it'll display the output below. To do this, we'll first need to import the md variable into our component (we'll put it in $.md) using a dynamic import(), and in the mean time we should show a loader. Next, we link $.input to the value in the textarea using live.link(), and lastly set up an effect() to render the output.

<title>markdown-editor</title> <template> <div #if="!$.md"> loading… </div> <template #else> <textarea></textarea> <div id="output"></div> </template> </template> <script> live.link($.$input, textarea); import('./md.js').then(({ md }) => $.md = md); const output = query('#output'); connected(() => { effect(() => { if(!$.md) return; output.innerHTML = $.md.render($.input); }); }); </script>

At first, $.md is undefined, causing the loader to be show, and the effect has an early return for when the imported module is not yet ready. Once it becomes available, the effect re-runs and uses the value of $.input, which has been bound to the textarea to render the Markdown. Since $.input is linked, it reactively updates based on changes in the textarea.

Animal sounds

For this example, we'll build a component that receives an animal in an animal attribute, and displays the noise (such as "meow") that animals makes. We'll have a boolean loud attribute, which causes the noise to be displayed in all-caps. Additionally, we'll expose an .alert() method on the element, and a read-only property .isMammal. Our component definition might look something like

<title>animal-sound</title> <meta attribute="animal" type="string" default="cat"> <meta attribute="loud" type="boolean"> <meta method="alert"> <meta property="isMammal" readonly> <template> {{ $.loud ? $.noise.toUpperCase() : $.noise }} </template> <script> const animals = { cat: { noise: 'meow', isMammal: true }, dog: { noise: 'woof', isMammal: true }, fish: { noise: 'blub', isMammal: false }, frog: { noise: 'croak', isMammal: false }, }; live.link($.$data, () => animals[$.animal]); live.link($.$noise, () => $.data?.noise ?? ''); live.link($.$isMammal, () => $.data?.isMammal ?? false); $.alert = () => { window.alert($.loud ? $.noise.toUpperCase() : $.noise); } </script>

Let's go through what's happening here, starting from the <script>. First, we define some data; this is our small database of sorts, and includes all the animals we want to support with the animal attribute. Next, we bind the relevant data from said database to the $.data variable. This stays up-to-date; if the component's .animal property or animal attribute changes, then $.data updates with it. This allows us to just read $.data from here on out instead of having to worry about which animal we need to use. As such, we can define $.noise and $.isMammal just from reading $.data. The latter is exposed to the custom element because we defined it through <meta property=…>. The former, $.noise is used only internally. Lastly, we define the $.alert() method, since we declared it using <meta method=…>. This means our custom element gets that .alert() method as well. Inside the <template>, similar to the logic in the .alert() method, we check if we need to use uppercase or not and display the animal sound.

See also