@uncinq/component-tokens 1.9.3 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/_index.md ADDED
@@ -0,0 +1,102 @@
1
+ ---
2
+ isIndex: false
3
+ title: component-tokens
4
+ description: Component-scoped CSS design tokens, layer 3 of the architecture, mapping semantic values onto the parts of a component.
5
+ weight: 3
6
+ icon: puzzle
7
+ ---
8
+
9
+ Component tokens are CSS custom properties scoped to a single UI component. They sit at the top of the [DTCG](dtcg/) three-layer model.
10
+
11
+ ```
12
+ primitive → semantic → component
13
+ (raw values) (purpose) (component-scoped)
14
+ ```
15
+
16
+ Where primitive and semantic tokens come from [@uncinq/design-tokens](../design-tokens/), component tokens map those semantic values onto specific parts of a component.
17
+
18
+ ```css
19
+ /* semantic token, from @uncinq/design-tokens */
20
+ --color-brand: var(--color-sienna-600);
21
+
22
+ /* component token, from this package */
23
+ --btn-color-background: var(--color-brand);
24
+ ```
25
+
26
+ A component token answers **"which semantic value does this part of this component use?"**.
27
+
28
+ ## Why the indirection is worth it
29
+
30
+ A component could read `--color-brand` directly. The extra hop buys two things.
31
+
32
+ **A seam to override.** A project can restyle buttons alone by setting `--btn-color-background`, without touching the brand color and therefore without moving every other branded element.
33
+
34
+ **A place to record intent.** `--btn-color-text: var(--color-text-on-brand)` documents that button text has to contrast against the brand color, which is an accessibility decision. Read directly, that decision would be invisible.
35
+
36
+ The rule that keeps the indirection honest: a component token **always references a semantic token**, never a raw value and never a primitive. When you find yourself wanting a raw value, the semantic layer is usually missing a token.
37
+
38
+ ## What is covered
39
+
40
+ 26 components, one JSON source and one generated CSS file each, 390 tokens in total.
41
+
42
+ | | | |
43
+ | --- | --- | --- |
44
+ | `alert` | `figure` | `map` |
45
+ | `badge` | `heading` | `media` |
46
+ | `breadcrumb` | `hero` | `modal` |
47
+ | `button` | `item` | `nav` |
48
+ | `card` | `items` | `pagination` |
49
+ | `carousel` | `link` | `surtitle` |
50
+ | `container` | `list` | `table` |
51
+ | `details` | `logo` | |
52
+ | `drawer` | | |
53
+ | `dropdown` | | |
54
+ | `embed` | | |
55
+
56
+ `card` is an alias layer over `item`, which is the canonical card-like unit. See the [Reference](reference/) for what each one actually declares.
57
+
58
+ ## Installation
59
+
60
+ This package resolves its references against `@uncinq/design-tokens`, which must be imported first.
61
+
62
+ ```bash
63
+ npm install @uncinq/design-tokens @uncinq/component-tokens
64
+ ```
65
+
66
+ ```css
67
+ @import '@uncinq/design-tokens';
68
+ @import '@uncinq/component-tokens';
69
+ ```
70
+
71
+ Per component, when you only need a few:
72
+
73
+ ```css
74
+ @import '@uncinq/design-tokens';
75
+ @import '@uncinq/component-tokens/css/components/button.css';
76
+ @import '@uncinq/component-tokens/css/components/badge.css';
77
+ ```
78
+
79
+ Without a build step:
80
+
81
+ ```html
82
+ <link rel="stylesheet" href="https://unpkg.com/@uncinq/design-tokens">
83
+ <link rel="stylesheet" href="https://unpkg.com/@uncinq/component-tokens">
84
+ ```
85
+
86
+ Import order matters here in a way it does not for most packages. These tokens are `var()` references, resolved by the browser at use time rather than at import time, so a missing design-tokens import does not error: it silently yields invalid values and unstyled components.
87
+
88
+ ## Where to go next
89
+
90
+ | Page | Covers |
91
+ | --- | --- |
92
+ | [Naming](naming/) | The naming grammar and the rules that keep it consistent |
93
+ | [Customizing](customizing/) | Overriding a component token, and when to add one |
94
+ | [Reference](reference/) | Every token for all 26 components, generated from the sources |
95
+ | [DTCG format](dtcg/) | The authoring format, including group-level types |
96
+ | [Style Dictionary](style-dictionary/) | The build, and how cross-package references resolve |
97
+
98
+ ## References
99
+
100
+ - [@uncinq/design-tokens](https://github.com/uncinq/design-tokens), the primitive and semantic layers
101
+ - [@uncinq/css-components](https://github.com/uncinq/css-components), the CSS that consumes these tokens
102
+ - [DTCG specification](https://tr.designtokens.org/format/)
@@ -0,0 +1,76 @@
1
+ ---
2
+ isIndex: false
3
+ title: Customizing
4
+ description: How to override a component token, which layer to reach for, and when a new token is warranted.
5
+ weight: 2
6
+ icon: sliders
7
+ ---
8
+
9
+ ## CSS override
10
+
11
+ Every token is declared in `@layer tokens`, the lowest-priority layer in the recommended order. Re-declare any of them in your own `@layer tokens` block after the import. Same layer, later source order wins, and no specificity escalation is needed.
12
+
13
+ ```css
14
+ @import '@uncinq/design-tokens';
15
+ @import '@uncinq/component-tokens';
16
+
17
+ @layer tokens {
18
+ :root {
19
+ --btn-color-background: var(--color-light);
20
+ --btn-border-radius: 0;
21
+ --hero-height: 80svh;
22
+ }
23
+ }
24
+ ```
25
+
26
+ ## Choosing the right layer to override
27
+
28
+ This is the decision that matters, and it is easy to get wrong in a way that only shows up later.
29
+
30
+ | You want to change | Override | Effect |
31
+ | --- | --- | --- |
32
+ | The brand color everywhere | `--color-brand` (semantic) | Every component reading brand follows |
33
+ | Buttons only | `--btn-color-background` (component) | Buttons alone, brand untouched |
34
+ | One button variant | The variant's own token, or a local scope | Narrower still |
35
+
36
+ Reach for the **semantic** layer by default. Overriding a component token is the right call only when you genuinely mean "buttons differ from everything else here". Doing it because it was the first token you found produces a design system that drifts component by component, which is the exact failure mode the three-layer split exists to prevent.
37
+
38
+ ## Scoped overrides
39
+
40
+ Because these are custom properties, they inherit. Setting one on a container rather than on `:root` restyles a region without a new class or a new token.
41
+
42
+ ```css
43
+ .promo-section {
44
+ --btn-color-background: var(--color-light);
45
+ --btn-color-text: var(--color-text-on-light);
46
+ }
47
+ ```
48
+
49
+ Every button inside `.promo-section` picks it up. This is usually better than inventing `--btn-promo-color-background`, because the variation is contextual rather than a new permanent concept.
50
+
51
+ Note that this works outside `@layer tokens` too. A scoped override is a normal declaration on a normal selector, so it competes on specificity like any other rule, not on layer order.
52
+
53
+ ## Adding a token
54
+
55
+ Only add a component token when a component genuinely needs a knob that does not exist. Before doing so, check three things:
56
+
57
+ 1. **Does a semantic token already express it?** If so, reference it rather than creating a new name.
58
+ 2. **Does the semantic layer need it instead?** If two components would want the same value for the same reason, it belongs in [@uncinq/design-tokens](../../design-tokens/), not here.
59
+ 3. **Does the name follow the grammar?** See [Naming](../naming/). A token that does not sort with its siblings will be missed by whoever looks for it next.
60
+
61
+ To add one, edit the JSON source and rebuild:
62
+
63
+ ```bash
64
+ npm install
65
+ npm run build
66
+ ```
67
+
68
+ Nothing else needs updating. Both the per-component CSS and `dist/css/index.css` are generated from files discovered on disk, so a new `tokens/components/*.json` is picked up automatically. See [Style Dictionary](../style-dictionary/).
69
+
70
+ ## What not to do
71
+
72
+ **Do not edit `dist/`.** Every file there carries a generated header and is overwritten on the next build.
73
+
74
+ **Do not override a token to a raw value when a semantic one exists.** `--btn-color-background: #3f51b5` works, but it leaves dark mode, theming and contrast pairing behind. `var(--color-indigo-600)` keeps the value inside the system.
75
+
76
+ **Do not fork the package to change values.** The CSS override above exists so that you do not have to. A fork means inheriting the maintenance of 26 components for what is usually a handful of lines.
package/docs/dtcg.md ADDED
@@ -0,0 +1,250 @@
1
+ ---
2
+ isIndex: false
3
+ title: DTCG format
4
+ description: The Design Tokens Community Group JSON format as used for component tokens, including group-level types.
5
+ weight: 4
6
+ icon: braces
7
+ ---
8
+
9
+
10
+ The [W3C Design Token Community Group (DTCG)](https://www.w3.org/community/design-tokens/) defines a standard interchange format for design tokens, so they can travel between tools (Figma, code, documentation) without loss of meaning.
11
+
12
+ `@uncinq/design-tokens` uses DTCG JSON as its source format. [Style Dictionary v5](https://styledictionary.com/) transforms those JSON files into CSS custom properties — see [STYLE-DICTIONARY.md](STYLE-DICTIONARY.md) for the build pipeline. The DTCG spec informs the architecture (primitive → semantic → component, naming conventions, token types).
13
+
14
+ ---
15
+
16
+ ## The DTCG format
17
+
18
+ The [DTCG spec](https://tr.designtokens.org/format/) defines tokens as JSON objects with reserved `$`-prefixed keys:
19
+
20
+ ```json
21
+ {
22
+ "color": {
23
+ "brand": {
24
+ "$value": "oklch(0.530 0.195 22.0)",
25
+ "$type": "color",
26
+ "$description": "Primary brand color — used for CTAs and highlights."
27
+ }
28
+ }
29
+ }
30
+ ```
31
+
32
+ > **Note on OKLCH:** The DTCG `color` type accepts any valid CSS color value, including `oklch(…)`. `@uncinq/design-tokens` uses OKLCH throughout — perceptually uniform, wide-gamut, and natively supported in modern browsers.
33
+
34
+ | Key | Required | Description |
35
+ | --- | --- | --- |
36
+ | `$value` | ✅ | The token's value |
37
+ | `$type` | recommended | The token type (see below) |
38
+ | `$description` | optional | Human-readable documentation |
39
+
40
+ ---
41
+
42
+ ## DTCG token types
43
+
44
+ ### Scalar types
45
+
46
+ | Type | Example value | CSS usage |
47
+ | --- | --- | --- |
48
+ | `color` | `oklch(0.530 0.195 22.0)` | `color`, `background-color` |
49
+ | `dimension` | `1rem`, `4px` | `width`, `padding`, `font-size` |
50
+ | `fontFamily` | `"system-ui, sans-serif"` | `font-family` |
51
+ | `fontWeight` | `700` | `font-weight` |
52
+ | `duration` | `300ms` | `transition-duration` |
53
+ | `cubicBezier` | `[0.165, 0.84, 0.44, 1]` | `animation-timing-function` |
54
+ | `number` | `1.5` | `line-height`, `opacity` |
55
+ | `string` | `"uppercase"` | free-form text values |
56
+ | `strokeStyle` | `"solid"`, `"dashed"` | `border-style` |
57
+
58
+ ### Composite types
59
+
60
+ | Type | Shape | CSS usage |
61
+ | --- | --- | --- |
62
+ | `shadow` | `{offsetX, offsetY, blur, spread, color}` | `box-shadow` |
63
+ | `border` | `{width, style, color}` | `border` shorthand |
64
+ | `transition` | `{duration, delay, timingFunction}` | `transition` shorthand |
65
+ | `typography` | `{fontFamily, fontSize, fontWeight, letterSpacing, lineHeight}` | typography rules |
66
+ | `gradient` | `{gradientType, stops[]}` | `background: linear-gradient(…)` |
67
+
68
+ → Full type list: [tr.designtokens.org/format/#types](https://tr.designtokens.org/format/#types)
69
+
70
+ > **Note on `clamp()` values:** DTCG has no native `fluid` type. Fluid tokens (`--font-size-fluid-sm`, `--font-size-fluid-md`, `--spacing-fluid-*`) use `$type: "dimension"` as the closest match — a documented gap in the spec.
71
+
72
+ ---
73
+
74
+ ## Token groups
75
+
76
+ Tokens are organized in nested objects. Groups share a `$type` by inheritance:
77
+
78
+ ```json
79
+ {
80
+ "color": {
81
+ "$type": "color",
82
+ "gray": {
83
+ "100": { "$value": "oklch(0.967 0.003 264.542)" },
84
+ "900": { "$value": "oklch(0.208 0.006 264.542)" }
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ → [tr.designtokens.org/format/#groups](https://tr.designtokens.org/format/#groups)
91
+
92
+ ---
93
+
94
+ ## Naming conventions
95
+
96
+ ### CSS compound properties → camelCase
97
+
98
+ CSS property names that are two words (kebab-case in CSS) are written as a single **camelCase key** — not as a nested group. The `pathToKebab` transform converts them back to kebab-case for the CSS output, so the result is identical either way.
99
+
100
+ | JSON key | CSS custom property |
101
+ | --- | --- |
102
+ | `"fontFamily"` | `--btn-font-family` |
103
+ | `"fontSize"` | `--btn-font-size` |
104
+ | `"fontStyle"` | `--btn-font-style` |
105
+ | `"fontWeight"` | `--btn-font-weight` |
106
+ | `"lineHeight"` | `--btn-line-height` |
107
+ | `"maxHeight"` | `--btn-max-height` |
108
+ | `"maxWidth"` | `--btn-max-width` |
109
+ | `"textDecoration"` | `--btn-text-decoration` |
110
+ | `"textTransform"` | `--btn-text-transform` |
111
+
112
+ ```json
113
+ // ✅ correct
114
+ "btn": {
115
+ "fontSize": { "$value": "{fontSize.sm}", "$type": "dimension" },
116
+ "fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" }
117
+ }
118
+
119
+ // ❌ wrong
120
+ "btn": {
121
+ "font": {
122
+ "size": { "$value": "{fontSize.sm}", "$type": "dimension" },
123
+ "weight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" }
124
+ }
125
+ }
126
+ ```
127
+
128
+ **Exception — semantic namespaces:** `border`, `color`, `padding`, `margin`, `shadow` used to group multiple sub-properties stay nested, because the group key itself is not a CSS property compound word.
129
+
130
+ ```json
131
+ // ✅ border as a namespace grouping multiple properties
132
+ "border": {
133
+ "radius": { "$value": "{radius.control}", "$type": "dimension" },
134
+ "width": { "$value": "{border.width.sm}", "$type": "dimension" }
135
+ }
136
+
137
+ // ✅ color as a semantic grouping
138
+ "color": {
139
+ "background": { "$value": "{color.background.default}", "$type": "color" },
140
+ "text": { "$value": "{color.text.default}", "$type": "color" }
141
+ }
142
+ ```
143
+
144
+ ### Logical properties → sub-keys of `padding` / `margin`
145
+
146
+ Sub-axes of `padding` and `margin` use **CSS logical property names** as sub-keys — not physical directions (`x`, `y`, `top`, `bottom`, `left`, `right`).
147
+
148
+ | Sub-key | CSS logical property | Physical equivalent |
149
+ | --- | --- | --- |
150
+ | `"inline"` | `padding-inline` / `margin-inline` | left + right |
151
+ | `"block"` | `padding-block` / `margin-block` | top + bottom |
152
+ | `"inlineStart"` | `padding-inline-start` / `margin-inline-start` | left (LTR) |
153
+ | `"inlineEnd"` | `padding-inline-end` / `margin-inline-end` | right (LTR) |
154
+ | `"blockStart"` | `padding-block-start` / `margin-block-start` | top |
155
+ | `"blockEnd"` | `padding-block-end` / `margin-block-end` | bottom |
156
+
157
+ ```json
158
+ // ✅ correct
159
+ "padding": {
160
+ "inline": { "$value": "{spacing.sm}", "$type": "dimension" },
161
+ "block": { "$value": "{spacing.xs}", "$type": "dimension" }
162
+ }
163
+
164
+ // ❌ wrong
165
+ "padding": {
166
+ "x": { "$value": "{spacing.sm}", "$type": "dimension" },
167
+ "y": { "$value": "{spacing.xs}", "$type": "dimension" }
168
+ }
169
+ ```
170
+
171
+ **Exception — CSS `top`/`bottom`/`left`/`right` as positioning values** (not margin/padding sub-keys) keep their physical names, since they map to CSS position properties, not logical shorthands.
172
+
173
+ ```json
174
+ // ✅ positioning — physical names are correct here
175
+ "sticky": {
176
+ "top": { "$value": "4rem", "$type": "dimension" }
177
+ }
178
+ ```
179
+
180
+ ### States → nested sub-keys
181
+
182
+ Interactive states (`default`, `hover`, `active`, `disabled`…) are expressed as **nested keys** under the property they modify. The `default` key is automatically stripped by the build transform.
183
+
184
+ ```json
185
+ "color": {
186
+ "background": {
187
+ "default": { "$value": "{color.brand.default}", "$type": "color" },
188
+ "hover": { "$value": "{color.brand.hover}", "$type": "color" }
189
+ }
190
+ }
191
+ ```
192
+
193
+ ```css
194
+ /* output */
195
+ --btn-color-background: var(--color-brand);
196
+ --btn-color-background-hover: var(--color-brand-hover);
197
+ ```
198
+
199
+ States and camelCase properties compose naturally:
200
+
201
+ ```json
202
+ "color": {
203
+ "textDecoration": {
204
+ "default": { "$value": "transparent", "$type": "color" },
205
+ "hover": { "$value": "{color.link.default}", "$type": "color" }
206
+ }
207
+ }
208
+ ```
209
+
210
+ ```css
211
+ --btn-color-text-decoration: transparent;
212
+ --btn-color-text-decoration-hover: var(--color-link);
213
+ ```
214
+
215
+ ---
216
+
217
+ ## References (aliases)
218
+
219
+ Tokens can reference other tokens using `{dotted.path}` syntax:
220
+
221
+ ```json
222
+ {
223
+ "color": {
224
+ "link": {
225
+ "default": {
226
+ "$value": "{color.brand.default}",
227
+ "$type": "color"
228
+ }
229
+ }
230
+ }
231
+ }
232
+ ```
233
+
234
+ In CSS, this maps to `var()`:
235
+
236
+ ```css
237
+ --color-link: var(--color-brand);
238
+ ```
239
+
240
+ This is the key mechanism behind the **primitive → semantic → component** hierarchy.
241
+
242
+ → [tr.designtokens.org/format/#alias](https://tr.designtokens.org/format/#alias)
243
+
244
+ ---
245
+
246
+ ## References
247
+
248
+ - [DTCG specification](https://tr.designtokens.org/format/) — W3C Community Group draft
249
+ - [DTCG GitHub](https://github.com/design-tokens/community-group) — issues, discussion
250
+ - [Style Dictionary v5](https://styledictionary.com/) — token build pipeline, see [STYLE-DICTIONARY.md](STYLE-DICTIONARY.md)
package/docs/naming.md ADDED
@@ -0,0 +1,119 @@
1
+ ---
2
+ isIndex: false
3
+ title: Naming
4
+ description: The component token naming grammar, the rules behind it, and why colors invert the usual property order.
5
+ weight: 1
6
+ icon: tag
7
+ ---
8
+
9
+ Every component token follows one pattern:
10
+
11
+ ```
12
+ --{component}-{property}-{sub-property?}-{state?}
13
+ ```
14
+
15
+ | Pattern | Example |
16
+ | --- | --- |
17
+ | `--{component}` | `--btn` |
18
+ | `--{component}-{property}` | `--btn-padding-inline` |
19
+ | `--{component}-{property}-{sub-property}` | `--btn-color-text-decoration` |
20
+ | `--{component}-{property}-{state}` | `--btn-color-background-hover` |
21
+
22
+ The property mirrors the CSS property name, so a token reads the same way as the declaration it controls. `--btn-padding-inline` drives `padding-inline`. Colors are the one exception, explained below.
23
+
24
+ ## Rules
25
+
26
+ **Lowercase kebab-case**, always.
27
+
28
+ **Component name first**: `--btn-*`, `--badge-*`, `--hero-*`. This is what makes the tokens greppable and what keeps them sorted together in the generated CSS.
29
+
30
+ **Reference a semantic token whenever the value is a shared design decision.** Colors, spacing, radii, typography and motion should all be `var(--some-semantic-token)`, so that overriding the semantic layer moves every component at once.
31
+
32
+ About 80% of the tokens in this package do exactly that. The remaining fifth carry raw values, and legitimately so. They fall into four groups:
33
+
34
+ | Group | Examples |
35
+ | --- | --- |
36
+ | CSS keywords with no semantic equivalent | `transparent`, `none`, `solid`, `start`, `auto`, `underline` |
37
+ | Identity values | `--badge-border-width: 0`, `--container-max-width-mobile: 100%` |
38
+ | Geometry specific to one component | `--drawer-width: 320px`, `--dropdown-min-width: 12rem`, `--drawer-translate: translateX(100%)` |
39
+ | Content and computed values | `--breadcrumb-separator: "/"`, `--hero-height: clamp(...)`, `--hero-media-brightness: 0.5` |
40
+
41
+ The test to apply is whether another component would ever want the same value for the same reason. If yes, it belongs in the semantic layer and should be referenced from there. If no, a raw value here is correct, and inventing a semantic token for it would only add a hop that means nothing.
42
+
43
+ **States go last**: `-hover`, `-focus`, `-active`, `-disabled`.
44
+
45
+ **Alphabetical order within each group**, with a comment introducing each group once a component has many properties.
46
+
47
+ ```css
48
+ /* Border */
49
+ --btn-border-radius: var(--radius-control);
50
+ --btn-border-width: var(--border-width-sm);
51
+
52
+ /* Color */
53
+ --btn-color-background: var(--color-brand);
54
+ --btn-color-border: var(--color-brand);
55
+ --btn-color-text: var(--color-text-on-brand);
56
+ --btn-color-text-decoration: transparent;
57
+
58
+ /* Spacing */
59
+ --btn-gap: var(--spacing-xs);
60
+ --btn-padding-block: var(--spacing-control);
61
+ --btn-padding-inline: var(--spacing-control);
62
+ ```
63
+
64
+ ## Why colors invert the order
65
+
66
+ For every other property the token mirrors the CSS property name. For colors it does not: `color` leads and the UI role follows.
67
+
68
+ | Token | Role | CSS property it drives |
69
+ | --- | --- | --- |
70
+ | `--btn-color-background` | background | `background-color` |
71
+ | `--btn-color-border` | border | `border-color` |
72
+ | `--btn-color-text` | text | `color` |
73
+ | `--btn-color-text-decoration` | text-decoration | `text-decoration-color` |
74
+ | `--form-color-accent` | accent | `color` |
75
+ | `--input-color-placeholder` | placeholder | `color` |
76
+
77
+ Writing `--btn-background-color` would have been more faithful to CSS, but it scatters a component's colors across the alphabet, between `--btn-border-radius` and `--btn-padding-block`. Leading with `color` groups them into one contiguous block in the generated file and in an editor's autocomplete.
78
+
79
+ It also makes the component token mirror the global one. `--color-background` becomes `--btn-color-background`, so the relationship between the two layers is visible in the name.
80
+
81
+ `background` is never abbreviated. It is `color-background`, never `color-bg`.
82
+
83
+ ## The `default` convention
84
+
85
+ In the JSON source, a state lives in a nested key, and `default` is the unstated one. The build strips it from the generated name.
86
+
87
+ ```json
88
+ {
89
+ "btn": {
90
+ "color": {
91
+ "background": {
92
+ "default": { "$value": "{color.brand.default}", "$type": "color" },
93
+ "hover": { "$value": "{color.brand.hover}", "$type": "color" }
94
+ }
95
+ }
96
+ }
97
+ }
98
+ ```
99
+
100
+ produces:
101
+
102
+ ```css
103
+ --btn-color-background: var(--color-brand);
104
+ --btn-color-background-hover: var(--color-brand-hover);
105
+ ```
106
+
107
+ Note that the stripping happens on both sides. `{color.brand.default}` becomes `var(--color-brand)`, matching what `@uncinq/design-tokens` actually emits.
108
+
109
+ ## Compound CSS properties
110
+
111
+ A CSS property with a hyphen is written in camelCase in JSON, and the build converts it back.
112
+
113
+ | JSON path | CSS custom property |
114
+ | --- | --- |
115
+ | `btn.paddingInline` | `--btn-padding-inline` |
116
+ | `btn.color.textDecoration` | `--btn-color-text-decoration` |
117
+ | `item.borderRadius` | `--item-border-radius` |
118
+
119
+ Use logical properties (`inline`, `block`, `inlineStart`, `blockEnd`) rather than physical ones (`left`, `right`, `top`, `bottom`), so that a component works in a right-to-left context without a second set of tokens. See [DTCG format](../dtcg/) for the full list of conventions.