Skip to content

Authoring a component

UI Patterns 2 are SDC components, with a few additions and some better practices.

So, we expects the reader to be already comfortable with SDC before reading this chapter which is complementing the SDC documentation: https://www.drupal.org/docs/develop/theming-drupal/using-single-directory-components

UI Patterns 2 is adding the links metadata property for documentation, with both a compact and a full syntax:

name: Example
links:
  - "https://test.com"
  - url: "https://example.com"
    title: "Example"
props: {}
slots: {}

Tags metadata

For documentation only:

name: Example
tags: [Foo, Bar, Baz]
slots: {}
props: {}

Component variants

A “variants” property is available in component definition.

Variants are a “glorified” prop but it is still a prop. This property was added:

  • to ease the experience of the front developer which doesn't need to set a schema for an already well known data type
  • because JSON schema enums have no label and using a anyOf with constant is verbose and complicated
  • to show this prop will have a special treatment
  • to be able to put variant prop (and this prop only) before slots in the form builder trait.

YAML:

name: Card
variants:
  default:
    title: Default
    description: An ordinary card.
  highlighted:
    title: Highlighted
    description: A special card.
slots: {}
props: {}

Once loaded, this property will also be available as a string prop with enum:

name: Card
props:
  type: object
  properties:
    variants:
      type: string
      enum: [default, highlighted]

So it can be manipulated like that in render elements, twig functions…

Related SDC ticket: https://www.drupal.org/project/drupal/issues/3390712

Explicit prop typing

Using JSON schema for props definition is enough for simple data:

  • type: string for the strings
  • type: [number, integer] for the numbers
  • type: string, format: uri for the URL
  • ...

For more complicated data, we need "shortcuts", because it may be difficult for component authors to type complex schema without errors.

Those shortcuts are based on a JSON schema references provider with ui-patterns:// URL scheme.

So, instead of writing the full prop schema, a component every prop type plugin is a JSON schema reference. For example:

props:
  type: object
  properties:
    figcaption_attributes:
      title: "Figcaption attributes"
      description: "The attributes to customize the figcaption tag."
      "$ref": "ui-patterns://attributes"

JSON Schema processors can resolve this $ref and build the complete schema to validate

It is important to understand the URI is opaque. In ui-patterns://attributes the word "attributes" means nothing. No information must be guessed from that. Only the data retrieved from the request is relevant.

UI Patterns is then working on the already resolved JSON schema.

UI Patterns 2.x is shipped with some prop type plugins included.

Attributes

Reference shortcut: ui-patterns://attributes

Resolved schema:

type: object
patternProperties:
  ".+":
    anyOf:
      - type:
          - string
          - number
      - type: array
        items:
          anyOf:
            - type: number
            - type: string

The value is transformed into an \Drupal\Core\Template\Attribute object before being sent to the template.

Boolean

Reference shortcut: ui-patterns://boolean

It is better to use the resolved schema:

type: boolean

Default form widget: a checkbox.

List of enums

Reference shortcut: ui-patterns://enum_list

Resolved schema:

type: array
items:
  type:
    - string
    - number
    - integer
  enum: []

Because the enum values are expected, it is better to use directly the schema like that:

type: array
minItems: 2
maxItems: 4
items:
  enum: [Apple, Banana, Cocoa]

With two optional properties used in the component form:

  • minItems to set the number of required values (default: 0)
  • maxItems to set the number of values (default: 1)

Default form widget: A maxItems number of select lists.

Enum

A single value restricted to a fixed set of values.

Reference shortcut: ui-patterns://enum

Resolved schema:

type: ["string", "number", "integer"]
enum: []

It is better to use the resolved schema with only the enum values:

enum:
  - "Foo"
  - "Bar"
  - "Baz"
enum:
  - 5
  - 10
  - 15

Default form widget: A select list.

Set of enums

Set of unique predefined string or number items.

Reference shortcut: ui-patterns://enum_set

Resolved schema:

type: array
uniqueItems: true
items:
  type:
    - string
    - number
    - integer
  enum: []

It is necessary to set the enum values:

ui-patterns://enum_set
items:
  enum: ["Foo", "Bar", "Baz"]

Default form widget: A checkbox for each value.

Identifier

A string with restricted characters, suitable for an HTML ID.

Reference shortcut: ui-patterns://attributes

Resolved schema:

type: string
pattern: '(?:--|-?[A-Za-z_\x{00A0}-\x{10FFFF}])[A-Za-z0-9-_\x{00A0}-\x{10FFFF}\.]*']

Default form widget: A textfield.

A list of link objects. Useful to model menu, breadcrumbs, pagers...

Reference shortcut: ui-patterns://links

Resolved schema:

type: array
items:
  type: object
  properties:
    title:
      type: string
    url:
      "$ref": ui-patterns://url
    attributes:
      "$ref": ui-patterns://attributes
    link_attributes:
      "$ref": ui-patterns://attributes
    below:
      type: array
      items:
        type: object

Default form source: A Drupal menus selector.

List

List of free string or number items.

Reference shortcut: ui-patterns://list

Resolved schema:

type: array
items:
  type: [string, number, integer]

Default form widget: A textarea. One value per line.

Number

Reference shortcut: ui-patterns://number

It is better to use the resolved schema:

  • for a decimal value: type: number
  • for an integer value: type: integer

Default form widget: a number textfield with incremental steps (0.01 for decimal)

It is possible to set minimum and/or maximum values:

type: integer
minimum: 1789
maximum: 2025

String

Reference shortcut: ui-patterns://string

It is better to use the resolved schema:

type: string

Default form widget: a textfield.

URL

Reference shortcut: ui-patterns://url

Resolved schema:

type: string
format: iri-reference

Default form widget: a textfield.

Prop default values

UI Patterns 2 uses default when building the component form, as #default_value.

default must not be used in the rendering process (sending default value if prop value is missing or empty) because:

  • sometimes we want a default value in forms while allowing the user to set empty or missing value
  • the |default() Twig filter is the expected tool for such an enforcement

meta:enum

For your information, in UI Patterns 2, we use meta:enum which is not an official standard but supported by some popular projects:

  • https://github.com/adobe/jsonschema2md
  • https://github.com/coveooss/json-schema-for-human
props:
  type: object
  properties:
    position:
      type: string
      enum:
        - top
        - bottom
      "meta:enum":
        top: Top
        bottom: Bottom

So:

  • If an item is in enum but not in meta:enum, its label will be the item string
  • If an item is in meta:enum but not in enum, it is ignored.