[community-group] Tokens group $extends property proposal (#116)

jorenbroekema has just created a new issue for https://github.com/design-tokens/community-group:

== Tokens group $extends property proposal ==
# Tokens group $extends property proposal

I would like to propose adding a special `$extends` property on token groups to signify that the group extends from another group.
This proposal is mostly focusing on components being tokenized rather than core/base or semantic tokens, although perhaps you can use this for such tokens as well.

For example, an input-amount component may conceptually extend the input component, with 95% overlap and only a few design decisions that differ.

Instead of duplicating 95% of the tokens, it's more likely that token authors will only tokenize the parts of input-amount that differ from the input. For more context, [I wrote a bit about token explicitness here](https://backlight.dev/blog/design-tokens)

Throughout this proposal I'm using an example with 2 components. An input component with 2 tokens: field width and field background. An input-amount component that reuses the regular input's field background, but changes the field width, so it has only 1 token but reuses another.

Base `input.tokens.json`:

```json
{
  "input": {
    "field": {
      "width": { 
        "$value": "100%"
      },
      "background": { 
        "$value": "#FFFFFF"
      }
    }
  }
}
```

Extension `input.tokens.json`:

```json
{
  "input-amount": {
    "$extends": "{input}",
    "field": {
      "width": { "value": "100px" }
    }
  }
}
```

The `$extends` prop signifies that the input-amount token group extends from the input token group.

## Use cases

I'll try to explain some use cases here to show why this information could potentially be valuable for design token tools. Feel free to add your own!

### Token analysis

Let's say we want to analyze our tokens and create a big diagram to show relationships between tokens. When one component's tokens conceptually extends another's tokens, this information is relevant to such diagrams, otherwise you won't get the full picture and it will look like the input-amount only has 1 token.

### Discoverability

When token authors are changing, removing or adding token values, it helps to be able to see that one token group extends another. Without this information, they may change tokens in the wrong location e.g. they want to change the background-color of all inputs, but by accident they end up doing it for every extension input individually, creating unnecessary duplication of tokens.

### Autosuggest/complete

When your input-amount tokens only have a field width property, consumers of these tokens or the output of these tokens might get confused.

Let's imagine for a second that we do CSS in JS, so we exported our tokens to a custom JS format. A developer will now implement this component separately.

```js
import { css } from 'lit';
import { inputAmountTokens as t } from './input-amount-tokens.js';

const inputAmountStyles = css`
  .btn {
    width: ${t.width};
    background-color: ${t.background}; /* ?? :( */
  }
`;
```

t.background will error as being undefined, because unknowing to the developer, this token is the same for input and input-amount, therefore they should import that from the `input-tokens.js`. This may not be intuitive, however, with the `$extends` information we may be able to give an auto-suggestion on hover or at least display in the hover on inputAmountTokens that it inherits from the regular inputTokens.

### Explicit tokens output

Usually when there's a lot of overlap between component tokens, I personally tend to say you should be minimal and not duplicate your tokens everywhere, reuse what you can, at least in your tokens source of truth. This makes maintenance easier.

However, I can imagine it might be preferable for some platforms to have very explicit token output. So in our example, instead of only getting:

- `input-field-background`
- `input-field-width`
- `input-amount-field-width`

You would also get `input-amount-field-background`, even though the value is exactly the same as `input-field-background` and therefore duplicate.

In the token parsing and formatting process, the `$extends` property would be used to essentially do something like this:

before:

```js
const tokens = {
  input: {
    field: {
      width: { 
        $value: "100%"
      },
      background: { 
        $value: "#FFFFFF"
      }
    }
  },
  "input-amount": {
    $extends: "{input}",
    field: { // no background prop
      width: { "value": "100px" }
    }
  }
}
```

after:

```js
const tokens = {
  input: {
    field: {
      width: { 
        $value: "100%"
      },
      background: { 
        $value: "#FFFFFF"
      }
    }
  },
  "input-amount": {
    ...tokens.input,
    field: {
      ...tokens.input.field, // has the background prop
      width: { "value": "100px" }
    }
  }
}
```

Basically, a deep merge will be done using the `$extends`, which can chain up recursively e.g. if input extends another component tokens file etc.

In this way you will have the full result of any tokens that you're extending from, explicitly in the output format.

### Theming

When theming, most of the design decisions remain the same across themes, and a few ones change based on theme. I'm not exactly sure if there is yet a best practice for managing themes inside design tokens, but I can imagine that if you go with a "parent-child-inheritance" type of syntax, this spec proposal may be applicable for theming. However, my personal preference is combining theme values inside a single token value, but that's just me..:

```json
{
  "$value": {
    "light": "{colors.text.dark}",
    "dark": "{colors.text.light}"
  }
}
```

Let me know what you guys think about the proposal, whether there is indeed a need, how you would change the API, other use cases, etc.


Please view or discuss this issue at https://github.com/design-tokens/community-group/issues/116 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Wednesday, 9 March 2022 09:38:36 UTC