Component

A component consists of a View, that is implemented as HTML template with its own CSS, and a Controller that is the Javascript code that controls the view, its presentation and the interaction logic.

Component's files are placed in the same path location and their base name is the same, and it represents itself the component's name:

The unique identifier of the component is therefore its full path, formed by the <path> of the component plus the <component_name> without any extension.

<component_id> :== [<path>/]<component_name>

Components can be loaded by adding the z-load attribute to a host element, with its value containing a valid component identifier:

<div z-load="<component_id>"></div> 

The <path> of the component can be either relative to the page requesting the component, or an absolute path even if pointing to a different server. In the latter case, CORS must be enabled on the server end in order to allow fetching of components from the remote server.

If the <path> is relative and not starting with a ".", the lookup folder will be the application folder, which is by default "/app".

For example, consider the following time-clock component with its files placed into a widgets folder:

in this case the <component_id> is widgets/time-clock, so the component can be loaded into the HTML page by using the following code:

<div z-load="widgets/time-clock"></div>
Loading widgets/time-clock...

so, basically, the view template (time-clock.html + time-clock.css) is rendered inside the host element div, and the controller code (time-clock.js) is activated and begins to animate the clock's digits.

sports_soccer Try this in the Playground

Custom element

It is possible to define a custom element for a zuix.js component by using the zuix.loadComponent(..) method:

customElements.define('component-name', class extends HTMLElement {
  connectedCallback() {
    zuix.loadComponent(this, 'path/of/component-name');
  }
});

After defining a custom element, the component can be added to the page by using the custom element tag:

<component-name></component-name>

which has the same effect of using the z-load attribute on a host element:

<div z-load="path/of/component-name"></div>

Defining a custom element for a Material Design button component.

customElements.define('mdl-button', class extends HTMLElement {
  connectedCallback() {
    zuix.loadComponent(this, '@lib/controllers/mdl-button', 'ctrl');
  }
});

The third parameter <type> can be supplied to the zuix.loadComponent(..) in case we are loading only a controller (ctrl) or only a view template (view), rather than a complete component (.html + .css + .js).

Using the mdl-button element in the page:

<mdl-button :class="'primary'">
    Hello
</mdl-button>

<mdl-button :type="'flat'">
    Web
</mdl-button>

<mdl-button :class="'accent'">
    Components
</mdl-button>

HelloWebComponents
sports_soccer Try this in the Playground

Shadow DOM

With custom elements it is also possible to enable the shadow DOM.
zuix.js will auto-detect if a custom element is using shadow DOM when the attachShadow method is called with the mode option set to open. If the mode is otherwise set to closed, then the shadow DOM must be passed explicitly as a container with the zuix.loadComponent(..) options as shown in the following example:

JS

customElements.define('time-clock', class extends HTMLElement {
    connectedCallback() {
        zuix.loadComponent(this, 'widgets/time-clock', '', {
            container: this.attachShadow({mode: 'closed'})
        });
    }
});

HTML

<time-clock></time-clock>

Standalone components

Standalone components are components that can be loaded by just importing a single JavaScript module. They can be easily implemented by adding the following lines at the end of the controller code:

File: widgets/time-clock.js (example)

// bottom of controller class code... 
const customTag = 'time-clock';
const componentId = 'widgets/time-clock';
// register component class
zuix.controller(TimeClock, {componentId});

const setup = () => {
  // Create custom element <time-clock></time-clock>
  customElements.define(customTag, class extends HTMLElement {
    connectedCallback() {
      zuix.loadComponent(this, componentId);
    }
  });
};
// Load zuix.js if not already loaded  
if (self.zuix === undefined) {
  import('https://cdn.jsdelivr.net/npm/zuix-dist@1.1.29/js/zuix.module.min.js')
    then(() => setup());
} else setup();

Then the component module can be imported in the head section of the page

...
<head>
    ...
    <script type="module" src="/app/widgets/time-clock.js"></script>
    ...
</head>
...

or using the import statement, or the dynamic import() function, inside another module

import "/app/widgets/time-clock.module.js"

then, the component, can be added inside the page's body using the defined tag

<time-clock></time-clock>

Since the code above is already loading zuix.js library with the import at line #16, there's no need to include zuix.min.js in the head section of the page and so, the component can be loaded with just one line of of code.

The URL of the imported module can also be an absolute URL pointing to a different server.

Note that the additional code above, can also be implemented into a separate file, e.g. time-clock.module.js, but the registration of component class must be removed (lines #4-5).

try Example on CodePen
sports_soccer Try this in the Playground

View-only component

It's also possible to load just a view without the controller and so consisting of the two files:

To load a view, the type-attribute view is added to the host element.

<div view z-load="<component_id>">
  <!-- loaded view content will be rendered here -->
</div> 

In the example below the view template named links is loaded using an absolute URL path:

<div view z-load="https://zuixjs.org/app/content/docs/examples/links"></div>

Loading component examples/links...

Controller-only component

A controller-only component, or simply controller, is basically a component whose view is the host element itself. To load a controller the type-attribute ctrl is added to the host element.

<div ctrl z-load="<component_id>">
  <!-- host element content -->
</div> 

A controller consists only of a Javascript file:

In the following example the Gesture Helper controller is added to a div container in order to detect swipe left and swipe right gestures over it.

<div ctrl z-load="@lib/controllers/gesture-helper"
     (gesture:swipe)="handleSwipeGesture">
  <strong>
      Gesture detection area
  </strong>
  <p>
      Try swiping left or right.
  </p>
</div>

<script>
  function handleSwipeGesture(e, tp) {
    switch (tp.direction) {

      case 'left':
        this.playAnimation('animate__fadeOutLeft');
        break;
 
      case 'right':
        this.playAnimation('animate__fadeOutRight');
        break;
 
      }
  }
}
</script>

Gesture detection area

Try swiping left or right.

The default component

Using the internal default component it is possible to get advantage of zuix.js components' features also on standard HTML elements.
Adding the z-load="default" attribute or any other z-* attribute to a div, will create a new component context where the div is its view template, and where it will be possible to use all templating and scripting capabilities of zuix.js components:

<div z-model="{number: 42}">
    
    <mdl-button :type="'fab'"
                (pointerdown)="model.number--">
        remove
    </mdl-button>

    <strong #number></strong>

    <mdl-button :type="'fab'"
                (pointerdown)="model.number++">
        add
    </mdl-button>

    <!-- SCOPED CSS: `media="#"` attribute 
         will apply styles only to the enclosing
         component context -->
    <style media="#">
        :host {text-align: center}
        strong {margin: 12px}
    </style>
</div>

removeadd
sports_soccer Try this in the Playground
Terms and concepts
Context Options
GitHub logo
JavaScript library for component-based websites and applications.