Die Komponenten verwenden

Attribute, Properties, Events und die Einbindung ins Framework.

Die Komponenten sind gewöhnliche Custom Elements. Alles Folgende ist reines DOM und braucht kein Framework; danach kommt, was die einzelnen Frameworks ergänzen.

Attribute und Properties

Jeder Parameter lässt sich entweder als HTML-Attribut oder als JavaScript-Property setzen. Die Schreibweise unterscheidet sich dabei:

  • Attribut im HTML, immer kleingeschrieben: iconright
  • Property aus JavaScript, in camelCase: iconRight
<!-- Attribut -->
<tuix-input iconright="search"></tuix-input>
<tuix-input descriptiontype="error" description="Pflichtfeld"></tuix-input>
// Property
input.iconRight = 'search'
input.descriptionType = 'error'

Jede Komponentenseite führt beide Namen nebeneinander auf. Die meisten Attribute sind der kleingeschriebene Property-Name, zwei werden mit Bindestrich geschrieben:

PropertyAttributElement
borderRadiusborder-radiustuix-paper
visibilityDurationvisibility-durationtuix-toast

Objekte und Arrays

Attributwerte sind immer Text. Parameter, die ein Objekt oder ein Array erwarten, werden deshalb als Property gesetzt:

ElementParameter
tuix-dropdownoptions, value
tuix-radio-buttonoptions
tuix-tabledata, headers, pageSizeOptions, loader
const table = document.querySelector('tuix-table')
table.headers = [{ name: 'Name', dataKey: 'name', width: 30 }]
table.data = [{ id: 1, name: 'Alice' }]

In einer reinen HTML-Seite gibt es dafür kein JavaScript, dort steht der Wert als JSON im Attribut:

<tuix-dropdown options='["Draft", "Sent", "Paid"]'></tuix-dropdown>

JSON kann keine Funktionen transportieren; eine Spalte mit cellColor muss deshalb als Property gesetzt werden.

Der nächste Abschnitt zeigt, wie die einzelnen Frameworks eine Property setzen.

Einen Parameter übergeben

Jeder Parameter gehört zu einer von fünf Arten, und jedes Framework hat je einen Weg dafür. Die Tabs zeigen dasselbe Dropdown dreimal: ein String, ein Enum, eine Objektliste, das gemeinsame Boolean dark und ein Event.

example.component.html
<tuix-dropdown
    title="Country"
    description="Pick a country"
    [type]="DropdownType.SEARCH"
    [descriptionType]="DescriptionType.ERROR"
    [options]="countries"
    [dark]="isDark"
    (select)="onSelect($event)"
></tuix-dropdown>
example.component.ts
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'
import { DescriptionType, DropdownType } from 'tuix-webcomponents'

@Component({
    selector: 'app-example',
    standalone: true,
    schemas: [CUSTOM_ELEMENTS_SCHEMA],
    templateUrl: './example.component.html',
})
export class ExampleComponent {
    readonly DescriptionType = DescriptionType
    readonly DropdownType = DropdownType

    readonly countries = [
        { name: 'Switzerland', value: 'CH' },
        { name: 'Germany', value: 'DE' },
    ]

    isDark = false

    onSelect(event: Event) {
        const { value } = (event as CustomEvent<{ value: string | number | boolean }>).detail
        console.log(value)
    }
}
ArtReines HTMLAngularVueReact
Stringtitle="Country"gleichgleichtitle="Country"
Enumtype="search"[type]:typetype={...}
Boolean, auch darkdark[dark]:darkdark={...}
Objekt oder ArrayJSON[options]:optionsoptions={...}
EventaddEventListener(select)@selectonSelect={...}

Dark Mode

Jedes Element ausser tuix-table nimmt ein Boolean dark entgegen. Kein Element liest ein globales Theme: die Anwendung übergibt dark pro Element, aus dem, womit sie das Theme verwaltet.

<tuix-button variant="primary" dark>Speichern</tuix-button>

dark erreicht, was eine Komponente selbst rendert: das Modal reicht es an seine Karte und sein Schliess-Icon weiter, Toast und Checkbox an das Label, das sie zeichnen. Was in sie hineingeslottet wird, erreicht es nie. Eigener Inhalt bringt sein dark deshalb selbst mit:

<tuix-modal dark visible>
    <tuix-text slot="title" dark>Diese Vorlage löschen?</tuix-text>
    <tuix-button slot="actions" variant="primary" dark>Löschen</tuix-button>
</tuix-modal>

Diese eine Ausnahme will eingeplant sein: die tuix-text- und tuix-icon-Elemente der Tabelle bleiben hell, was die Seite auch tut. Ein dunkles Design gibt der Tabelle deshalb eine helle Fläche, statt sie umzuschalten.

Events

Die Komponenten melden sich über CustomEvents, die bubblen. Die Nutzlast liegt, wenn es eine gibt, in event.detail, bei den meisten Events also in event.detail.value:

document.querySelector('tuix-input').addEventListener('on-change', (event) => {
    console.log(event.detail.value)
})

Die drei Pagination-Events von tuix-table sind die Ausnahme: sie tragen event.detail.page und event.detail.pageSize und gar keinen value. Checkbox und Toggle stellen neben den Wert noch event.detail.label.

Die Namen sind bewusst nicht die nativen: ein Button feuert customClick, ein Input on-change. Die vollständige Liste steht unter Events.

Nur die Pagination-Events von tuix-table überqueren die Shadow-Grenze (composed: true). Alle anderen bubblen innerhalb des Baums, in dem sie gefeuert wurden, also genau dort, wo ein normaler Listener am Element oder an einem seiner Vorfahren sie sieht.

Im Framework

Jedes Framework braucht etwas Vorbereitung: eine Wrapper-Bibliothek für React, ein Compiler-Flag für Vue, ein Schema für Angular. Je ein Guide, und danach lässt sich jedes Beispiel auf den Komponentenseiten in dem Framework lesen, das in den Tabs darüber gewählt ist:

Reines HTML

Das Bundle wird mit den zwei Tags aus der Installation geladen. Deren URLs enthalten das Release und werden deshalb dort generiert statt hier ausgeschrieben. Danach sind die Elemente einfache Tags:

<tuix-paper elevation="2" border-radius="10px">
    <tuix-text size="l" color="section">Rechnung</tuix-text>
    <tuix-button variant="primary" iconleft="download">Herunterladen</tuix-button>
</tuix-paper>
 
<script>
    document.querySelector('tuix-button').addEventListener('customClick', () => {
        window.print()
    })
</script>

Slots und Layout

Textinhalt kommt in den Default-Slot des Elements, und die Komponenten mit mehreren Bereichen benennen ihre Slots (tuix-modal: title, body, actions; tuix-table: ein Slot pro Zelle). Weil der Inhalt im Light DOM bleibt, greifen die Styles der Seite weiterhin auf ihn; isoliert ist nur das Innenleben der Komponente.

Auf dieser Seite