Skip to content

Web components

...

Common concepts

Common model concepts

We can use the flags model to set the value from the parent component. Otherwise, the component will manage its state (model value) internally:

model can be manipulated using javaScript. Some helpers are provided in the @zurich/dev-utils package to ease this process:

html
<!DOCTYPE html>
<html>
  <body>
    <z-text-input id="my-text-input" label="Text input"/>

    <script type="module">
      const textInputEl = document.getElementById('my-text-input')

      if (textInputEl) textInputEl.value === true;
    </script>
  </body>
</html>
html
<!DOCTYPE html>
<html>
  <body>
    <z-text-input id="my-text-input" label="Text input"/>
    <output id="my-text-input-output"></output>

    <script type="module">
      const textInputEl = document.getElementById('my-text-input')
      const textInputOutput = document.getElementById('my-text-input-output');

      let textInputValue = false;

      if (textInputEl) onSwitchValueChange(textInputEl)
      
      textInputEl?.addEventListener('change', ({ detail }) => {
        onSwitchValueChange(detail)
      })

      function onSwitchValueChange (value) {
        textInputValue = value;
        toggleAttribute(textInputEl, 'model', value);
        textInputOutput.innerText = value;
      }

      function toggleAttribute (element, attrName, value) {
        if (value === undefined) element.setAttribute(attrName, value)
        else element.removeAttribute(attrName)
      }
    </script>
  </body>
</html>
html
<!DOCTYPE html>
<html>
  <body>
    <z-text-input id="my-text-input" label="Text input"/>
    <output id="my-text-input-output"></output>

    <script type="module">
      import { bindInputChange } from '@zurich/dev-utils/helpers';

      const textInputEl = document.getElementById('my-text-input')
      const textInputOutput = document.getElementById('my-text-input-output');

      let textInputValue = false;

      if (textInputEl) textInputOutput.innerText = value;
      
      bindInputChange(textInputEl, (value) => {
        textInputValue = value;
        textInputOutput.innerText = value;
      })
    </script>
  </body>
</html>

label

The label can be set as a parameter:

Or using the label slot

Slotted labelSlotted label

This allow us to build up more complex things like a hint in the input label:

I agree the Terms and conditions

Slotted label

disabled

The disabled flag avoid any UI interaction with the input as it would be done with a regular HTMLInputElement, making the element not mutable, focusable, or even submitted with the form.

name

Defines the name use un the form for that field. Must be unique in the form. Follows the HTML standard.

required

As with the regular HTMLInputElement API, indicates that the user must specify a value for the input before the owning form can be submitted.

help-text

Not every input has the help-text option.

The help-text can be set as a parameter or using the help-text slot:

Slotted help text

This allow us to build up more complex things in the help text:

Complex help text

In boolean inputs this text will only be shown if a label is provided:

reset() method

A method of the input web components to reset the value.

Boolean inputs

They are inputs that are always going to manage a boolean as the model value.

The available Web boolean inputs are:

model and checked

We can use the flags value or checked to set the value:

Boolean inputs validation

The validation of the inputs can be controlled using the invalid attribute:

The required property will make the boolean input invalid if this is not set to true. The invalid state will disappear it the value is set to true:


Inputs

They are inputs that are always going to manage a model value different from a boolean. In some occasions this can also be an array or object.

The available Web inputs are:

model

We can use the attribute value to set the value:

Some inputs with complex model require the values properly stringified:

options

Some of the inputs, like CheckboxGroup, CheckboxSelect, Select, or RadioSelect have the options attribute. This is a complex one that needs to be specified in a JSON stringified format.

These options can be individually disabled:

But alternately, <option> tags in the default slot can be use for better readability and SEO:

max-length

The TextInput and Textarea components allow the use of max-length attribute.

No counter

We recommend to use the max-length counter for UX purposes, but there are some instances where this counter might pollute the form too much. We strongly recommend to apply this only to TextInput and not to Textarea.

Wwe can use CSS:

css
z-text-input::part(output) {
  display: none;
}

Or using the no-counter flag for TextInput:


Form inputs

Are inputs but with validation mechanisms.

The available Web form inputs are:

config

It's an attribute that defines the general style of the input:

Can also modify the general size:

placeholder

Most inputs can show a placeholder text when they are empty to show extra instructions.

readonly

Form inputs can used as outputs using the readonlyflag.

reset()

We can all the reset() method of the WebComponent in order to reset the value. This will clean the internal states and emit the nullable value with the change event, plus a restarted event:

In this example, the button triggers the method:

Value:  undefined

Inputs validation

The validation of the inputs can be controlled using the invalid flag. In combination with help-text, you can also provide some feedback about the error.

Not every input has the invalid option.

When the required flag is set, the invalid state will be shown when the input is touched.

The message shown is this cases would be Required field.

Attention!

invalid is a HTML flag, that means that <z-input invalid="false"/> will still be considered as invalid. If you're using a boolean to set the attribute, use a binding with an OR to undefined.

The framework wrappers are managing this for you, so you can use pure booleans.

More info in flag.


Vue

v-model

Vue has the v-model directive to manage the two-way data binding. But this comes with the twist of having to use specific naming for the value attribute and the change event, set as modelValue and onUpdate:modelValue respectively.

Here's an example of use:

vue
<script lang="ts" setup>
import { ref } from 'vue';
import { ZvCheckbox } from '@zurich/web-components/vue';

const value = ref(false);
</script>

<template>
  <code><b>Value:</b> {{ value }}<code>
  <zv-checkbox v-model="value"/>
</template>

An example of this in StackBlitz:


Angular

ngModel

Angular has the [(ngModel)] directive to manage the two-way data binding. But this comes with the twist of having to use specific naming for the value attribute and the change event, that will be changed to ngModel and ngModelChange respectively.

You can use this naming without import FormsModule due to the standardization done in our Angular wrappers.

Here's an example of use:

ts
import { Component } from '@angular/core';
import { ZaCheckbox } from '@zurich/angular-components';

@Component({
  standalone: true,
  imports: [ZaCheckbox],
  template: `
    <code><b>Value:</b> {{ value }}<code>
    <za-checkbox [(ngModel)]="value"/>
  `,
})
export class Checkbox {
  value = false;
}

Reactive Forms

The components of @zurich/angular-components are prepared to use Angular's Reactive Forms. The @angular/forms package is already part of the dependencies

ts
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { ZaButton, ZaCheckboxSelect } from '@zurich/angular-components';

@Component({
  standalone: true,
  imports: [CommonModule, ZaCheckboxSelect, ZaButton, ReactiveFormsModule],
  template: './app.component.html',
})
export class ReactiveForm {
  readonly fruitOptions: ZaCheckboxSelect['options'] = [
    { text: 'Banana', value: 'banana' },
    { text: 'Orange', value: 'orange' },
    { text: 'Kiwi', value: 'kiwi' },
  ];

  form = new FormGroup({
    fruit: new FormControl(['banana']),
  });

  setValue() { this.form.controls.fruit.setValue(['kiwi']); }

  resetValue() { this.form.controls.fruit.reset(); }
}
html
<form [formGroup]="form">
  <za-checkbox-select label="Fruits" formControlName="fruit" [options]="fruitOptions"/>
  
  <code><b>Value:</b> {{ form.get('fruit')?.value }}</code>

  <div>
    <za-button config="secondary:xs" (click)="setValue()">Set</za-button>
    <za-button config="negative:xs" (click)="resetValue()">Reset</za-button>
  </div>
</form>

An example of this in StackBlitz:

Attention!

We strongly recommend the use of encapsulation of forms with all the inputs being controlled via ReactiveFormsModule in a single component. The combination of ReactiveFormsModule and the use of [(ngModel)] can lead to errors like:

shell
ERROR Error NG0201: No provider for NgControl found in NodeInjector.

This can be bypassed by adding FormsModule to the imports and the using the ngDefaultControl attribute in the ZDS inputs that are using [(ngModel)]. But we recommend not to use this approach, but the form encapsulation.