Skip to content

How it works

The ZDS development libraries try to adapt to the multiple use cases that we have inside Zurich when it comes to applications development. That requires to have tooling that is flexible, progressive, and that can deal with all the minor issues by hiding the management of the complexity of use and configuration under simplified interfaces that are still giving the control to the developer and the app environment to make the integration as easy as possible.

Design tokens

Design tokens are the building blocks of all UI elements. In ZDS, tokens are CSS custom properties that can be used to style or customize components or element at different levels, but also as a way of avoiding hard-coded values with implementations done on top of ZDS.

In order to simplify the design, improve consistency, allow customization, and make the whole ZDS more systematic, we use the concept of design token during the design phase (by using Figma variables) and for our development libraries (by using CSS custom properties, AKA CSS variables).

The main difference between this type of variables and the ones used in CSS preprocessors like Sass (SCSS) is that these variables work at runtime and keep the references, they are not simple placeholders substituted in transpilation time.

This is translated in the end into a base NPM package called @zurich/design-tokens that any other web-based components package will be using.

Multi-paradigm

We need to give support to multiple platforms, frameworks, and workflows with this design system. That's why we have develop two different approaches to use the designed components:

CSS components

Our CSS components based in pure HTML and CSS with no extra libraries required. It's the one implemented in the @zurich/css-components package. Uses custom HTML attributes for the CSS selectors that are not part of the standard ones and also the standard ones of each HTML standard tag.

In the documentation of each component you will find a select in to top-right corner of the page to change between the different explanations of the implementations (for paradigm and target framework). In the cases where the component it's only implemented via WebComponent, the CSS option won't appear.

Web Components

Web components are custom HTML elements with encapsulated styles and behavior. They work across many different frameworks (such as Lit, React, Vue, and Svelte) as well as web environments (such as Eleventy, Wordpress, and Ruby on Rails).

Our Web components use Lit as the only dependency and are JS-based components that have the CSS already included inside the JS files. Each component has also a wrapper to be used as a "native" component for the three main frontend frameworks: Angular, React and Vue. It's the one implemented in the @zurich/web-components package (React and Vue) and @zurich/angular-components (Angular).

Native mobile components

Native mobile components: we offer also libraries for frameworks that allow the development of native apps like React Native with our @zurich/react-native package.

Local installation vs Remote code

Every package can be installed locally, or imported via URL as part of the meta of the HTML document (except for the SCSS tooling of @zurich/dev-utils, since it requires transpilation to CSS in order to be usable).

Each option has pros and cons.

Remote code

It's done through <script> and/or <link rel="stylesheet"> tags in the <head> or <body> of the document and are the easiest way of start using the ZDS. For further information about the import process of each package; check the corresponding installation guide. And for consuming assets: check the consumables description.

This approach doesn't require development dependencies and allow to use the design system directly from the HTML documents. Allows to have a more fine control over the necessary assets to improve performance and doesn't require a bundler.

It's the approach used in the examples of this documentation.

For example, the imports of using the CSS paradigm:

html
<script type="module" src="/0.5.2/@zurich/css-components/javascript.js"></script>
<link rel="stylesheet" href="/0.5.2/@zurich/design-tokens/HeadingTags.css" />
<link rel="stylesheet" href="/0.5.2/@zurich/design-tokens/Icons.css" />
<link rel="stylesheet" href="/0.5.2/@zurich/css-components/index.css" />

Or using the Web Components paradigm:

html
<link rel="stylesheet" href="/0.5.2/@zurich/web-components/styles.css" />
<link rel="stylesheet" href="/0.5.2/@zurich/design-tokens/HeadingTags.css" />
<script type="module" src="/0.5.2/@zurich/web-components/index.js"></script>

Local installation

It's done via NPM packages and requires further configuration depending on the framework used. One of the advantages of the local installation is that we could be using all the TypeScript and JSDocs features of the components. Check the corresponding installation guide per package.

This approach offers the best developer Experience (DX) since allows the use of TypeScript and JSDocs to receive hints, errors, autocompletion, and documentation about all the aspects of the ZDS directly in the IDE.

For example, for installing the CSS components in your project, use this command in the root of the project (same level as the package.json):

sh
npm i -D @zurich/css-components

Or for Web Components:

sh
npm i -D @zurich/web-components

Customization

Customization levels

By using the overwrite of some defined CSS variables we can customize the design system if it's required for a certain project. We explicitly expose those variables as part of the documentation so you have no issues with the customization and can make everything work with very easy steps.

There are three customization categories or levels to consider.

General or app

By changing the design token in the :root CSS pseudo-element or under the body selector, we can change variables for the whole site to adapt the design system to our requirements. The last option (with body) even allow us to create different theme based on complementary selectors (ex.: body.my-theme or body[theme="my-theme"]).

Some examples of this selectors:

css
:root {
  --z-button--bg: red;
}
css
body {
  --z-button--bg: red;
}
css
body[theme="scarlet"] {
  --z-button--bg: red;
}

In every example, the value of the variable --z-heading--color is changed to red for the entire page.

Contextual

By using selector for specific container components (ex.: #my-container) or direct injection in the style attribute the customization can be scoped under that container or under circumstances. This is basically how our z-theme works.

html
<section id="my-container">
  <z-button>Click me!</z-button>
</section>
css
#my-container {
  --z-button--bg: red;
}
Instance

As with the contextual customization, the modifications can de applied to a single tag or component instance to make adjustments or fine component customization.

html
<z-button style="--z-button--bg: red;">Click me!</z-button>
<z-button custom='{ "bg": "red "}'>Click me!</z-button>
<z-button custom-str="bg: red;">Click me!</z-button>

Custom theme

By using the semantic tokens we can create custom theme as variations of the default ZDS look-and-feel in order to customize the UI for specific brands or purposes. These variables can be override on any of the previously mentioned levels.

The previously mentioned "contextual customization" approach allows to have multiple themes at the same time by using different selectors.

Custom components

Each component has it's own custom variables exposed with the naming convention --z-<component_name>--<property> as you can check in here, for example. This eases the process of adapting the components without the overhead of having to deal directly with the CSS and in a controlled and tested way.

These variables can be override on any of the previously mentioned levels.

For WebComponents, there are also two extra options for customizations:

  • Using the custom attribute, that requires a key-value pair object with the <property> name as key and the corresponding value as string.
html
<z-button custom='{ "bg": "red" }'>Click me!</z-button>
  • Using the custom-str attribute, that requires a string with the standard HTML object syntax.
html
<z-button custom-str="bg:red">Click me!</z-button>

Slots

WebComponents have the ability of using slots: placeholders inside a web component that you can fill with your own markup, which lets you create separate DOM trees and present them together.

The tooltip component, for example, uses the inner HTML of the tag to be the "tooltiped" element. This is consider as the default slot.

Hover me

These slots can also be named in order to target an specific one.

HeadBody

Slots in React

In React, the default slot works the same:

html
<ZrTooltip text="Information text">
  Hover me
</ZrTooltip>

But React does not have a proper approach for slots. Instead of that, it can receive other JSX elements as properties. Specific properties are created in the Reacts wrappers when the slot is not an already existing property.

tsx
function THead () {
  return (
    <thead>
      <tr><th>Head</th></tr>
    </thead>
  )
}

function TBody () {
  return (
    <tbody>
      <tr><td>Body</td></tr>
    </tbody>
  )
}

function App () {
  return <ZrTable THead={<THead/>} TBody={<TBody/>}/>
}