Quick Start

Welcome to this quick start tutorial for Live Elements. These chapters will guide you through most of the concepts in Live Elements and show you how to make the most out of the language.

We will go through:

  • Using the Playground
  • Declaring and creating components
  • Creating a UI and managing the DOM using components
  • Styling
  • Binding data and creating interactions
  • Components with scoped styles
  • Using ready made UI components

Playground

To practice all these concepts, we're going to use the Live Elements playground at play.liveelements.io.

If you want, you can also setup the playground offline. Simply install lvweb from live-elements-web-clipackage and use it to generate and run the playground on localhost:

mkdir playground
cd playground

npm i live-elements-web-cli # install lvweb

npx lvweb init --template playground # create the playground
npx lvweb serve # run the playground

The playground should now be running at localhost:8080.

If you have any trouble installing lvweb, you can checkout the installation page. It offers more information on installation and troubleshooting.

Using the playground

In the top left corner of the playground page, you will find the 'Open' icon. There's different projects you can open, they show different use cases with Live Elements.. We're going to open the Application (Console) project which is a template for a simple console application.

This will open the Index.lv file in the editor, with the following contents:

import live-web

component App < Application{
    run: () => {
        console.log('Application is now running.')
    }
}

We're going to go into more detail about the file structure, but for now, just note that the file imports live-webmodule. It's where the Application component is defined. Then, a new component is declared in the file, App component, which inherits from Application:

component App < Application{
    // ...
}

Components in Live Elements are similar to classes in javascript, they include most of the functionality from classes, but they have additional features, which we will cover in this guide. Components inherit from other components, which works similarly to class inheritance, and they use this inheritance symbol: <. Components can also have properties, in this case the run property is assigned by the App component. The run property is a function that's run by the playground when it loads the Index.lv file. Inside the run function, we can write javascript and live elements code.

We can already see the function was run in the playground, as we see the message Application is now running. in the console. To run the application again, we can either click on the 'compile' button in the top bar, or save the file after modifying it. Saving the file will trigger a compilation automatically. The file can be saved using cmd+s on Mac or ctrl+s on a pc.

Most of the coding in this part will be inside the run function.

Components

We've mentioned above that components are similar to javascript classes, and they inherit from other components. All components actually inherit the BaseElement component, similar to how all classes inherit the Object class in javascript.

A component inheriting directly from BaseElement does not need to write that implicitly:

component MyComponent{}
// is the same as
component MyComponent < BaseElement{}

Components are created using the curly braces:

let a = MyComponent{} // a is now assigned with an instance of MyComponent

You can try this out in the run function:

import live-web

component App < Application{
    run: () => {
        component MyComponent{}; // declare MyComponent
        let a = MyComponent{}; // create MyComponent
        console.log('New component created: ', a)
    }
}

You should now see: New component created: [object Object].

Notice we've mixed javascript code with live elements code. let a for example is in javascript, and MyComponent{} is in live elements. Live Elements simply acts as an extension to javascript, and the 2 languages can be mixed freely between each other.

Component Properties

Components can declare properties like this:

component MyComponent < BaseElement{
    number x : 20
}

const a = MyComponent{}
console.log(a.x) // 20

Properties in components bind automatically, meaning if a property references another, then changes to that other property will also update the current one. The example below shows property y referencing property x. This means that whenever property x changes, property y will also change:

import live-web

component App < Application{
    run: () => {
        component MyComponent < BaseElement{
            number x : 20
            number y : this.x
        };

        const a = MyComponent{}
        console.log(a.y) // Output: 20
        a.x = 30
        // Both x and y are now 30
        console.log(a.x, a.y) // Output 30 30
    }
}

Expression assigments also bind properties:

import live-web

component App < Application{
    run: () => {
        component MyComponent < BaseElement{
            number x : 20
            number y : 30
            number z : this.x + this.y // z is now bound to x and y
        };

        let a = MyComponent{}
        console.log(a.z) // Output: 50
        a.x = 30
        // z is now (x + y), which is 60
        console.log(a.z) // Output: 60
    }
}

Property assignments

Components can have their properties assigned during creation:

component MyComponent < BaseElement{
    number x : 20
    number y : 30
};

let a = MyComponent{
    x : 10
    y : 20
}
console.log(a.x + ' ' + a.y) // Output: 10 20

Bindings also work when assigning through creation:

let a = MyComponent{
    x: 10
    y: this.x
};
a.x = 20
console.log(a.y) // Output: 20

Try it out in the playground:

import live-web

component App < Application{
    run: () => {
        component MyComponent < BaseElement{
            number x : 20
            number y : 30
        };
        const a = MyComponent{
            x: 10
            y: this.x
        }
        a.x = 20
        console.log(a.y) // Output: 20
    }
}

Constructors

Constructors are declared similarly to javascript class constructors:

component MyComponent{

    constructor(x:number){
        super()
        this{}

        console.log("Created with x = " + x)
    }
}

The only difference is the required call to super and to this{} before adding any other instructions. The call to this{} initializes all the properties, events and bindings of the component.

Creating an object using a constructor with arguments can be done by using the dot (.) after the component name, followed by the list of parameters in paranthesis, and followed by the assignments in curly braces:

// without assignment
const b = MyComponent.(100){} // Output: Created with x = 100

// with assignment
const c = MyComponent.(100){ prop : 15 } // Output: Created with x = 100

The full playground version:

import live-web

component App < Application{
    run: () => {
        component MyComponent{
            constructor(x:number){
                super()
                this{}
                console.log('Created with x = ' + x)
            }
        };

        const b = MyComponent.(100){} // Output: Created with x = 100
    }
}

Quick text constructors

Components with constructors that have a single argument of type string can be created using the following notation:

let a = ComponentName`argument`
// instead of the longer version
let a = ComponentName.('argument'){}

See how MyComponent is created below:

import live-web

component App < Application{
    run: () => {
        component MyComponent{
            constructor(text:string){
                super()
                this{}
                console.log('Initialized with text = ' + text)
            }
        };
        
        // Standard notation
        let a = MyComponent.('Hello'){} // Output: Initialized with text = Hello
        // Shortcut
        let b = MyComponent`Hello` // Output: Initialized with text = Hello
    }
}

Children

A component can accept children by configuring a default property called children:

component MyComponent{
    default children
};

A component with a default property can have component objects created directly in it's body. The objects will be assigned as a list to the default property:

import live-web

component App < Application{
    run: () => {
        component MyComponent{
            default children
        };
        
        let a = MyComponent{
            BaseElement{} // child 0
            BaseElement{} // child 1
        }
        
        // Output: Total children: 2
        console.log('Total children:', a.children.length) 
    }
}

A component supports a single default property. The default keyword also acts as a placeholder for the Array<BaseElement> type. The following code:

component MyComponent{
    Array<BaseElement> children
}

let a = MyComponent{
    children: [BaseElement{}, BaseElement{}]
}

Is the same as:

component MyComponent{
    default children
}

let a = MyComponent{
    children: [BaseElement{}, BaseElement{}]
}

However, since the children property is also declared as default, we can also assign MyComponent children as such:

let a = MyComponent{
    BaseElement{}
    BaseElement{}
}

Conclusion & Next Step

This chapter went through some of the basics on Live Elements components. We can now start looking at how this a applies to creating webpages in the following chapter. We will also cover more things on components like events, functions, listeners and others, but we will introduce them as we progress.