This document provides an overview on how to use and create variants in our component library.

What are variants?

Variants are a valuable feature of our component library that enables you to build multiple versions of a base component. These versions can have different configurations of the settings.

The framework utilises a transformer pattern for variants, where the default settings for each layer are passed in and the variant transformer is applied to create the desired configuration.

Each component requires a base variant that usually returns the default settings as-is. However, in some cases, the base variant may modify the default settings of layouts or displays to enhance the user's experience.

Each variant you create will show in the Unless dashboard as a separate template.

variants

Three variants of the same bar component.

How to use variants

The first thing to create is the base variant. The most basic variant is one where no settings are modified. Here’s an example:

import {Variant} from '@unless/component-library.display.display'
import {
		compilerExport,
		deepCopy
} from '@unless/component-library.utils.helpers'

const base: Variant<MyDisplaySettings> = (settings) => deepCopy(setting)

export default base
compilerExport(MyComponent.defaultSettings, base)

Best practices to implement variants

Folder Structure

To locate the necessary files, the compiler looks for a folder called variants within the component package. Within this folder, there must be at least one variant with the filename base.ts.

Variant Function

The transformer function must conform to the type:

type Variant<T extends DisplaySettings> = 
		(settings: SettingsModel<T>) => SettingsModel<T>

To prevent in-place shifting of values, the passed-in settings should be dereferenced using the deepCopy helper function. Settings are JavaScript objects, and the compiler works recursively to compile them. Therefore, modifying a referenced object's settings could lead to unexpected behaviour.

compilerExport

This pertains specifically to Variants and is utilised by the compiler in the first step of the build pipeline to generate the complete settings file. Each component has a static method defaultSettings by default, which must be passed as the first argument to the compilerExport function. The second argument is the transformer function for the variant.

The default export is only used for previewing in the bit environment during development.

Complex variants

In the previous example, we explained how to create a simple variant that returns the default settings unaltered. However, for more complex variants, you can modify the values of the settings to create different configurations. For instance, you could adjust the size or colour of a component or modify its layout.

Here’s an example for a single-step component:

import {Variant} from '@unless/component-library.display.display'
import {
		compilerExport,
		deepCopy
} from '@unless/component-library.utils.helpers'

const myNewVariant: Variant<OverlaySettings> = (settings) => {
		const newSettings = deepCopy(settings) // De-referencing the settings
		
		const display = newSettings.instance.content.overlay
		const layout  = newSettings.instance.stepper.steps[0] as OneColumnSettings

		display.size.value = Size.Lg
		
		layout.header.title.value = "My Awesome Title"

		return newSettings
}

What’s Next