@scania/tegel-lite 0.0.3-rules-beta.7 → 0.1.0
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/README.md +0 -29
- package/dist/assets/icons/scania/microphone.svg +4 -0
- package/dist/assets/icons/scania/microphone_inactive.svg +7 -0
- package/dist/assets/icons/scania/notification_snooze.svg +6 -0
- package/dist/assets/icons/scania/paperclip.svg +3 -0
- package/dist/components.css +2036 -1807
- package/dist/global.css +3 -2
- package/dist/scania-variables.css +8 -0
- package/dist/tl-button.css +19 -0
- package/dist/tl-dropdown.css +36 -1
- package/dist/tl-folder-tabs.css +64 -0
- package/dist/tl-header.css +207 -51
- package/dist/tl-icon.css +16 -0
- package/dist/tl-inline-tabs.css +81 -0
- package/dist/tl-navigation-tabs.css +81 -0
- package/dist/tl-slider.css +1024 -1485
- package/dist/tl-text-field.css +32 -13
- package/package.json +3 -14
- package/.ai/rules/01-design-tokens.mdc +0 -318
- package/.ai/rules/02-components-forms.mdc +0 -396
- package/.ai/rules/03-components-display.mdc +0 -474
- package/.ai/rules/04-components-navigation.mdc +0 -358
- package/.ai/rules/05-guidelines.mdc +0 -144
- package/.ai/rules/06-patterns.mdc +0 -352
- package/.cursor/rules/tegel-lite/01-design-tokens.mdc +0 -317
- package/.cursor/rules/tegel-lite/02-components-forms.mdc +0 -395
- package/.cursor/rules/tegel-lite/03-components-display.mdc +0 -473
- package/.cursor/rules/tegel-lite/04-components-navigation.mdc +0 -357
- package/.cursor/rules/tegel-lite/05-guidelines.mdc +0 -143
- package/.cursor/rules/tegel-lite/06-patterns.mdc +0 -351
- package/.github/copilot-instructions.md +0 -2045
- package/AGENTS.md +0 -2045
- package/CLAUDE.md +0 -2045
- package/bin/setup-ai-rules.js +0 -368
- package/dist/tl-folder-tab.css +0 -87
- package/dist/tl-inline-tab.css +0 -80
- package/dist/tl-navigation-tab.css +0 -114
- package/dist/tl-textarea-mixins.css +0 -0
package/AGENTS.md
DELETED
|
@@ -1,2045 +0,0 @@
|
|
|
1
|
-
# @scania/tegel-lite — AI Coding Rules
|
|
2
|
-
|
|
3
|
-
> Auto-generated by `npm run generate:ai-rules`. Do not edit manually.
|
|
4
|
-
|
|
5
|
-
> Generated: 2026-02-17
|
|
6
|
-
|
|
7
|
-
## 01-design-tokens
|
|
8
|
-
|
|
9
|
-
# Design Tokens & Variables
|
|
10
|
-
|
|
11
|
-
## RULE: ALWAYS use design tokens instead of hardcoded values.
|
|
12
|
-
|
|
13
|
-
## Primitive Color Tokens (from scania-variables.css)
|
|
14
|
-
|
|
15
|
-
### Blue (Primary Brand)
|
|
16
|
-
|
|
17
|
-
| Token | Value |
|
|
18
|
-
| ------------------------- | --------- |
|
|
19
|
-
| `--scania-color-blue-50` | `#d8dde5` |
|
|
20
|
-
| `--scania-color-blue-100` | `#bacde8` |
|
|
21
|
-
| `--scania-color-blue-200` | `#87afe8` |
|
|
22
|
-
| `--scania-color-blue-300` | `#4a89f3` |
|
|
23
|
-
| `--scania-color-blue-400` | `#2a6ecf` |
|
|
24
|
-
| `--scania-color-blue-500` | `#2058a8` |
|
|
25
|
-
| `--scania-color-blue-600` | `#16417f` |
|
|
26
|
-
| `--scania-color-blue-700` | `#0f3263` |
|
|
27
|
-
| `--scania-color-blue-800` | `#041e42` |
|
|
28
|
-
| `--scania-color-blue-900` | `#001533` |
|
|
29
|
-
|
|
30
|
-
### Red (Secondary Brand / Danger)
|
|
31
|
-
|
|
32
|
-
| Token | Value |
|
|
33
|
-
| ------------------------ | --------- |
|
|
34
|
-
| `--scania-color-red-50` | `#ffdfe3` |
|
|
35
|
-
| `--scania-color-red-100` | `#ffb9b8` |
|
|
36
|
-
| `--scania-color-red-200` | `#fc8a88` |
|
|
37
|
-
| `--scania-color-red-300` | `#ea4851` |
|
|
38
|
-
| `--scania-color-red-400` | `#d1001b` |
|
|
39
|
-
| `--scania-color-red-500` | `#b20018` |
|
|
40
|
-
| `--scania-color-red-600` | `#8a0012` |
|
|
41
|
-
| `--scania-color-red-700` | `#6c0011` |
|
|
42
|
-
| `--scania-color-red-800` | `#480008` |
|
|
43
|
-
| `--scania-color-red-900` | `#350004` |
|
|
44
|
-
|
|
45
|
-
### Green (Success)
|
|
46
|
-
|
|
47
|
-
| Token | Value |
|
|
48
|
-
| -------------------------- | --------- |
|
|
49
|
-
| `--scania-color-green-50` | `#d3eee7` |
|
|
50
|
-
| `--scania-color-green-100` | `#9bd9c2` |
|
|
51
|
-
| `--scania-color-green-200` | `#65bda5` |
|
|
52
|
-
| `--scania-color-green-300` | `#009e7e` |
|
|
53
|
-
| `--scania-color-green-400` | `#008064` |
|
|
54
|
-
| `--scania-color-green-500` | `#00664f` |
|
|
55
|
-
| `--scania-color-green-600` | `#004c3b` |
|
|
56
|
-
| `--scania-color-green-700` | `#0a382e` |
|
|
57
|
-
| `--scania-color-green-800` | `#00251b` |
|
|
58
|
-
| `--scania-color-green-900` | `#001a12` |
|
|
59
|
-
|
|
60
|
-
### Yellow (Warning)
|
|
61
|
-
|
|
62
|
-
| Token | Value |
|
|
63
|
-
| --------------------------- | --------- |
|
|
64
|
-
| `--scania-color-yellow-50` | `#f9eec3` |
|
|
65
|
-
| `--scania-color-yellow-100` | `#f8e596` |
|
|
66
|
-
| `--scania-color-yellow-200` | `#f4d65d` |
|
|
67
|
-
| `--scania-color-yellow-300` | `#f1c21b` |
|
|
68
|
-
| `--scania-color-yellow-400` | `#eaad06` |
|
|
69
|
-
| `--scania-color-yellow-500` | `#b87c14` |
|
|
70
|
-
| `--scania-color-yellow-600` | `#975717` |
|
|
71
|
-
| `--scania-color-yellow-700` | `#6b3b10` |
|
|
72
|
-
| `--scania-color-yellow-800` | `#4d260a` |
|
|
73
|
-
| `--scania-color-yellow-900` | `#361b07` |
|
|
74
|
-
|
|
75
|
-
### Grey (Neutral)
|
|
76
|
-
|
|
77
|
-
| Token | Value |
|
|
78
|
-
| -------------------------- | --------- |
|
|
79
|
-
| `--scania-color-grey-00` | `#fff` |
|
|
80
|
-
| `--scania-color-grey-50` | `#f6f7f9` |
|
|
81
|
-
| `--scania-color-grey-100` | `#edeff3` |
|
|
82
|
-
| `--scania-color-grey-150` | `#e0e5eb` |
|
|
83
|
-
| `--scania-color-grey-200` | `#d1d7e0` |
|
|
84
|
-
| `--scania-color-grey-250` | `#b4becd` |
|
|
85
|
-
| `--scania-color-grey-300` | `#93a2b7` |
|
|
86
|
-
| `--scania-color-grey-350` | `#7e90a9` |
|
|
87
|
-
| `--scania-color-grey-400` | `#6e829f` |
|
|
88
|
-
| `--scania-color-grey-500` | `#5f728c` |
|
|
89
|
-
| `--scania-color-grey-600` | `#4e5e75` |
|
|
90
|
-
| `--scania-color-grey-700` | `#3a4554` |
|
|
91
|
-
| `--scania-color-grey-800` | `#242c37` |
|
|
92
|
-
| `--scania-color-grey-850` | `#1c222b` |
|
|
93
|
-
| `--scania-color-grey-900` | `#15181d` |
|
|
94
|
-
| `--scania-color-grey-950` | `#0e1013` |
|
|
95
|
-
| `--scania-color-grey-1000` | `#000` |
|
|
96
|
-
|
|
97
|
-
## Semantic Color Tokens (Light Mode)
|
|
98
|
-
|
|
99
|
-
Use these instead of primitive colors in layouts:
|
|
100
|
-
|
|
101
|
-
### Backgrounds
|
|
102
|
-
|
|
103
|
-
| Token | Usage |
|
|
104
|
-
| -------------------------------------------------------------------------- | ------------------------------------- |
|
|
105
|
-
| `--color-background-base` | Page/app base background |
|
|
106
|
-
| `--color-background-layer-01` | Primary card/section background |
|
|
107
|
-
| `--color-background-layer-02` | Secondary/nested background |
|
|
108
|
-
| `--color-background-layer-03` | Third-level nested background |
|
|
109
|
-
| `--color-background-overlay` | Modal/drawer backdrop |
|
|
110
|
-
| `--color-background-top` | Top-level surface |
|
|
111
|
-
| `--color-background-accent-primary-default` | Primary button background |
|
|
112
|
-
| `--color-background-accent-primary-hover` | Primary button hover |
|
|
113
|
-
| `--color-background-accent-primary-pressed` | Primary button pressed |
|
|
114
|
-
| `--color-background-accent-primary-disabled` | Disabled button background |
|
|
115
|
-
| `--color-background-accent-danger-default` | Danger action background |
|
|
116
|
-
| `--color-background-surface-100` through `--color-background-surface-1000` | Surface levels for subtle backgrounds |
|
|
117
|
-
|
|
118
|
-
### Text (Foreground)
|
|
119
|
-
|
|
120
|
-
| Token | Usage |
|
|
121
|
-
| ---------------------------------------- | ---------------------- |
|
|
122
|
-
| `--color-foreground-text-strong` | Primary text, headings |
|
|
123
|
-
| `--color-foreground-text-defined` | Secondary text, labels |
|
|
124
|
-
| `--color-foreground-text-soft` | Tertiary text |
|
|
125
|
-
| `--color-foreground-text-subtle` | Placeholder, hint text |
|
|
126
|
-
| `--color-foreground-text-disabled` | Disabled text |
|
|
127
|
-
| `--color-foreground-text-accent-default` | Link text |
|
|
128
|
-
| `--color-foreground-text-accent-visited` | Visited link |
|
|
129
|
-
| `--color-foreground-text-brand` | Brand-colored text |
|
|
130
|
-
|
|
131
|
-
### Borders
|
|
132
|
-
|
|
133
|
-
| Token | Usage |
|
|
134
|
-
| ---------------------------------------- | ---------------------- |
|
|
135
|
-
| `--color-foreground-border-strong` | Strong visible borders |
|
|
136
|
-
| `--color-foreground-border-soft` | Default input borders |
|
|
137
|
-
| `--color-foreground-border-subtle` | Hover borders |
|
|
138
|
-
| `--color-foreground-border-discrete` | Divider lines |
|
|
139
|
-
| `--color-foreground-border-accent-focus` | Focus ring color |
|
|
140
|
-
| `--color-foreground-border-disabled` | Disabled borders |
|
|
141
|
-
|
|
142
|
-
### Icons
|
|
143
|
-
|
|
144
|
-
| Token | Usage |
|
|
145
|
-
| ---------------------------------- | --------------- |
|
|
146
|
-
| `--color-foreground-icon-strong` | Primary icons |
|
|
147
|
-
| `--color-foreground-icon-defined` | Secondary icons |
|
|
148
|
-
| `--color-foreground-icon-soft` | Tertiary icons |
|
|
149
|
-
| `--color-foreground-icon-subtle` | Faint icons |
|
|
150
|
-
| `--color-foreground-icon-disabled` | Disabled icons |
|
|
151
|
-
|
|
152
|
-
### System / Status Colors
|
|
153
|
-
|
|
154
|
-
| Token | Usage |
|
|
155
|
-
| --------------------------------- | ------------------------- |
|
|
156
|
-
| `--color-system-success-default` | Success states (green) |
|
|
157
|
-
| `--color-system-success-discrete` | Success background tint |
|
|
158
|
-
| `--color-system-warning-default` | Warning states (yellow) |
|
|
159
|
-
| `--color-system-warning-discrete` | Warning background tint |
|
|
160
|
-
| `--color-system-danger-default` | Error/danger states (red) |
|
|
161
|
-
| `--color-system-danger-discrete` | Error background tint |
|
|
162
|
-
| `--color-system-info-default` | Info states (blue) |
|
|
163
|
-
| `--color-system-info-discrete` | Info background tint |
|
|
164
|
-
|
|
165
|
-
## Spacing Units
|
|
166
|
-
|
|
167
|
-
| Token | Value |
|
|
168
|
-
| ------------------- | ------- |
|
|
169
|
-
| `--scania-unit-0` | `0` |
|
|
170
|
-
| `--scania-unit-1` | `1px` |
|
|
171
|
-
| `--scania-unit-2` | `2px` |
|
|
172
|
-
| `--scania-unit-4` | `4px` |
|
|
173
|
-
| `--scania-unit-8` | `8px` |
|
|
174
|
-
| `--scania-unit-12` | `12px` |
|
|
175
|
-
| `--scania-unit-16` | `16px` |
|
|
176
|
-
| `--scania-unit-20` | `20px` |
|
|
177
|
-
| `--scania-unit-24` | `24px` |
|
|
178
|
-
| `--scania-unit-32` | `32px` |
|
|
179
|
-
| `--scania-unit-40` | `40px` |
|
|
180
|
-
| `--scania-unit-48` | `48px` |
|
|
181
|
-
| `--scania-unit-56` | `56px` |
|
|
182
|
-
| `--scania-unit-64` | `64px` |
|
|
183
|
-
| `--scania-unit-80` | `80px` |
|
|
184
|
-
| `--scania-unit-96` | `96px` |
|
|
185
|
-
| `--scania-unit-120` | `120px` |
|
|
186
|
-
|
|
187
|
-
## Dimension/Spacing Semantic Tokens
|
|
188
|
-
|
|
189
|
-
| Token | Value | Usage |
|
|
190
|
-
| -------------------------- | ------ | ----------------------- |
|
|
191
|
-
| `--dimension-space-tiny` | `4px` | Micro spacing |
|
|
192
|
-
| `--dimension-space-small` | `16px` | Default element spacing |
|
|
193
|
-
| `--dimension-space-medium` | `24px` | Section padding |
|
|
194
|
-
| `--dimension-space-large` | `48px` | Large gaps |
|
|
195
|
-
| `--dimension-space-huge` | `80px` | Hero sections |
|
|
196
|
-
|
|
197
|
-
## Border Radius Tokens
|
|
198
|
-
|
|
199
|
-
| Token | Value | Usage |
|
|
200
|
-
| ------------------------------------------ | -------- | -------------------------- |
|
|
201
|
-
| `--dimension-radius-narrow` | `4px` | Buttons, inputs, cards |
|
|
202
|
-
| `--dimension-radius-soft` | `8px` | Larger containers |
|
|
203
|
-
| `--dimension-radius-rounded` | `32px` | Chips, pills |
|
|
204
|
-
| `--dimension-radius-circle` | `9999px` | Avatars, circular elements |
|
|
205
|
-
| `--dimension-radius-for-surface-clickable` | `4px` | Clickable elements |
|
|
206
|
-
| `--dimension-radius-for-surface-field` | `4px` | Form fields |
|
|
207
|
-
|
|
208
|
-
## Font Families
|
|
209
|
-
|
|
210
|
-
| Token | Value | Usage |
|
|
211
|
-
| ------------------------------------- | ---------------------------- | ----------------------- |
|
|
212
|
-
| `--scania-font-family-display` | `scania sans headline` | Display/headline text |
|
|
213
|
-
| `--scania-font-family-default` | `scania sans` | Body/default text |
|
|
214
|
-
| `--scania-font-family-semi-condensed` | `scania sans semi condensed` | Side menu, compact text |
|
|
215
|
-
|
|
216
|
-
## Font Weights
|
|
217
|
-
|
|
218
|
-
| Token | Value |
|
|
219
|
-
| ------------------------------ | ----- |
|
|
220
|
-
| `--scania-font-weight-regular` | `400` |
|
|
221
|
-
| `--scania-font-weight-bold` | `700` |
|
|
222
|
-
|
|
223
|
-
## Motion/Animation Tokens
|
|
224
|
-
|
|
225
|
-
| Token | Value | Usage |
|
|
226
|
-
| ----------------------------------- | -------------------------------- | -------------------- |
|
|
227
|
-
| `--tds-motion-duration-fast-01` | `100ms` | Micro-interactions |
|
|
228
|
-
| `--tds-motion-duration-fast-02` | `150ms` | Quick transitions |
|
|
229
|
-
| `--tds-motion-duration-moderate-01` | `200ms` | Standard transitions |
|
|
230
|
-
| `--tds-motion-duration-moderate-02` | `300ms` | Moderate animations |
|
|
231
|
-
| `--tds-motion-duration-slow-01` | `400ms` | Complex animations |
|
|
232
|
-
| `--tds-motion-duration-slow-02` | `500ms` | Full animations |
|
|
233
|
-
| `--tds-motion-easing-scania` | `cubic-bezier(0.4, 0, 0, 1)` | Default easing |
|
|
234
|
-
| `--tds-motion-easing-enter` | `cubic-bezier(0.1, 0.9, 0.2, 1)` | Enter transitions |
|
|
235
|
-
| `--tds-motion-easing-exit` | `cubic-bezier(0.7, 0, 1, 0.5)` | Exit transitions |
|
|
236
|
-
|
|
237
|
-
---
|
|
238
|
-
|
|
239
|
-
# Typography
|
|
240
|
-
|
|
241
|
-
## Typography Scale (defined in scania-variables.css under `.scania`)
|
|
242
|
-
|
|
243
|
-
### Display (Hero/Marketing)
|
|
244
|
-
|
|
245
|
-
- **Display 01**: 216px / 183px LH / uppercase / Scania Sans Headline Bold
|
|
246
|
-
- **Display 02**: 156px / 148px LH / uppercase / Scania Sans Headline Bold
|
|
247
|
-
- **Display 03**: 112px / 106px LH / uppercase / Scania Sans Headline Bold
|
|
248
|
-
- **Display 04**: 80px / 80px LH / uppercase / Scania Sans Headline Bold
|
|
249
|
-
- **Display 05**: 56px / 56px LH / uppercase / Scania Sans Headline Bold
|
|
250
|
-
|
|
251
|
-
### Headlines
|
|
252
|
-
|
|
253
|
-
- **Headline 01**: 40px / 40px LH / uppercase / Scania Sans Headline Bold
|
|
254
|
-
- **Headline 02**: 32px / 32px LH / Scania Sans Bold / ls: -1.28px
|
|
255
|
-
- **Headline 03**: 24px / 24px LH / Scania Sans Bold / ls: -0.72px
|
|
256
|
-
- **Headline 04**: 20px / 24px LH / Scania Sans Bold / ls: -0.4px
|
|
257
|
-
- **Headline 05**: 16px / 24px LH / Scania Sans Bold / ls: -0.32px
|
|
258
|
-
- **Headline 06**: 14px / 16px LH / uppercase / Scania Sans Bold / ls: -0.28px
|
|
259
|
-
|
|
260
|
-
### Paragraphs / Body
|
|
261
|
-
|
|
262
|
-
- **Paragraph 01**: 24px / 32px LH / Scania Sans Regular / ls: -0.72px
|
|
263
|
-
- **Paragraph 02**: 20px / 24px LH / Scania Sans Regular / ls: -0.2px
|
|
264
|
-
- **Body 01**: 16px / 24px LH / Scania Sans Regular / ls: -0.32px
|
|
265
|
-
- **Body 02**: 14px / 20px LH / Scania Sans Regular / ls: -0.14px
|
|
266
|
-
|
|
267
|
-
### Component Text
|
|
268
|
-
|
|
269
|
-
- **Component Text 01**: 14px / 16px LH / ls: -0.14px
|
|
270
|
-
- **Component Text 02**: 14px / 20px LH / ls: -0.14px
|
|
271
|
-
- **Component Label 01**: 12px / 16px LH / ls: 0
|
|
272
|
-
- **Component Label 02**: 10px / 8px LH / ls: 0
|
|
273
|
-
- **Component Title 01**: 14px / 16px LH / ls: -0.14px
|
|
274
|
-
- **Component Title 02**: 10px / 16px LH / uppercase / ls: 0.8px
|
|
275
|
-
|
|
276
|
-
### Links
|
|
277
|
-
|
|
278
|
-
- **Link 01**: 16px / 24px LH / ls: -0.32px
|
|
279
|
-
- **Link 02**: 14px / 20px LH / ls: -0.14px
|
|
280
|
-
|
|
281
|
-
## Typography Usage in Components
|
|
282
|
-
|
|
283
|
-
Components use internal typography tokens like `--detail-02-*`, `--headline-07-*`, `--body-01-*` etc. These are automatically applied. Do NOT manually set font properties on Tegel components.
|
|
284
|
-
|
|
285
|
-
---
|
|
286
|
-
|
|
287
|
-
# Layout & Grid
|
|
288
|
-
|
|
289
|
-
Tegel Lite does not include a CSS grid utility system. Use standard CSS Grid/Flexbox with Tegel tokens:
|
|
290
|
-
|
|
291
|
-
```html
|
|
292
|
-
<div
|
|
293
|
-
class="scania tds-mode-light"
|
|
294
|
-
style="
|
|
295
|
-
display: grid;
|
|
296
|
-
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
297
|
-
gap: var(--dimension-space-small);
|
|
298
|
-
padding: var(--dimension-space-medium);
|
|
299
|
-
"
|
|
300
|
-
>
|
|
301
|
-
<!-- Grid items -->
|
|
302
|
-
</div>
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
## Layout Components
|
|
306
|
-
|
|
307
|
-
- **Header** (`.tl-header`) – Full-width app bar, fixed at top
|
|
308
|
-
- **Side Menu** (`.tl-side-menu`) – Navigation sidebar, collapsible
|
|
309
|
-
- **Footer** (`.tl-footer`) – Multi-section page footer
|
|
310
|
-
|
|
311
|
-
## Breakpoints (used in components)
|
|
312
|
-
|
|
313
|
-
| Breakpoint | Value | Usage |
|
|
314
|
-
| ---------- | -------- | ------------- |
|
|
315
|
-
| xs | `320px` | Mobile |
|
|
316
|
-
| sm | `384px` | Small mobile |
|
|
317
|
-
| md | `672px` | Tablet |
|
|
318
|
-
| lg | `992px` | Desktop |
|
|
319
|
-
| xl | `1056px` | Large desktop |
|
|
320
|
-
| xxl | `1312px` | Wide desktop |
|
|
321
|
-
| xxxl | `1584px` | Ultra-wide |
|
|
322
|
-
|
|
323
|
-
---
|
|
324
|
-
|
|
325
|
-
## 02-components-forms
|
|
326
|
-
|
|
327
|
-
# Form Components
|
|
328
|
-
|
|
329
|
-
## Button
|
|
330
|
-
|
|
331
|
-
**Classes**: `tl-button`, `tl-button--primary`, `tl-button--secondary`, `tl-button--ghost`, `tl-button--danger`
|
|
332
|
-
**Sizes**: `tl-button--xs` (24px), `tl-button--sm` (40px), `tl-button--md` (48px), `tl-button--lg` (56px)
|
|
333
|
-
**Modifiers**: `tl-button--full-width`, `tl-button--icon`, `tl-button--only-icon`
|
|
334
|
-
|
|
335
|
-
```html
|
|
336
|
-
<!-- Primary button (default) -->
|
|
337
|
-
<button class="tl-button tl-button--primary tl-button--md">
|
|
338
|
-
Primary Action
|
|
339
|
-
</button>
|
|
340
|
-
|
|
341
|
-
<!-- Secondary button -->
|
|
342
|
-
<button class="tl-button tl-button--secondary tl-button--md">Secondary</button>
|
|
343
|
-
|
|
344
|
-
<!-- Ghost button -->
|
|
345
|
-
<button class="tl-button tl-button--ghost tl-button--sm">Ghost</button>
|
|
346
|
-
|
|
347
|
-
<!-- Danger button -->
|
|
348
|
-
<button class="tl-button tl-button--danger tl-button--md">Delete</button>
|
|
349
|
-
|
|
350
|
-
<!-- Button with icon (text BEFORE icon) -->
|
|
351
|
-
<button class="tl-button tl-button--primary tl-button--icon tl-button--md">
|
|
352
|
-
Save
|
|
353
|
-
<span class="tl-icon tl-icon--save" aria-hidden="true"></span>
|
|
354
|
-
</button>
|
|
355
|
-
|
|
356
|
-
<!-- Icon-only button -->
|
|
357
|
-
<button
|
|
358
|
-
class="tl-button tl-button--only-icon tl-button--md"
|
|
359
|
-
aria-label="Settings"
|
|
360
|
-
>
|
|
361
|
-
<span class="tl-icon tl-icon--settings"></span>
|
|
362
|
-
</button>
|
|
363
|
-
|
|
364
|
-
<!-- Full width -->
|
|
365
|
-
<button
|
|
366
|
-
class="tl-button tl-button--primary tl-button--md tl-button--full-width"
|
|
367
|
-
>
|
|
368
|
-
Full Width
|
|
369
|
-
</button>
|
|
370
|
-
|
|
371
|
-
<!-- Disabled -->
|
|
372
|
-
<button class="tl-button tl-button--primary tl-button--md" disabled>
|
|
373
|
-
Disabled
|
|
374
|
-
</button>
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
**Structure Rules**:
|
|
378
|
-
|
|
379
|
-
- **Button with icon**: Text comes FIRST, then icon. Add `tl-button--icon` modifier. Icon should have `aria-hidden="true"`.
|
|
380
|
-
- **Icon-only button**: Add `tl-button--only-icon` modifier and `aria-label` for accessibility.
|
|
381
|
-
- **Size**: Always include a size modifier (--xs, --sm, --md, --lg).
|
|
382
|
-
- **Variant**: Primary, secondary, ghost, or danger (optional, defaults to primary).
|
|
383
|
-
|
|
384
|
-
**Do's**:
|
|
385
|
-
|
|
386
|
-
- Always put text before icon in buttons with icons
|
|
387
|
-
- Always add `aria-hidden="true"` to decorative icons in buttons with text
|
|
388
|
-
- Always use `aria-label` for icon-only buttons
|
|
389
|
-
|
|
390
|
-
**Don'ts**:
|
|
391
|
-
|
|
392
|
-
- Never use `<div>` as a button
|
|
393
|
-
- Never style buttons with custom colors
|
|
394
|
-
- Never put icon before text in buttons with text
|
|
395
|
-
|
|
396
|
-
---
|
|
397
|
-
|
|
398
|
-
## Text Field (Input)
|
|
399
|
-
|
|
400
|
-
**Classes**: `tl-text-field`, `tl-text-field--lg` (56px, default), `tl-text-field--md` (48px), `tl-text-field--sm` (40px)
|
|
401
|
-
**Variants**: `tl-text-field--primary`, `tl-text-field--secondary`, `tl-text-field--label-inside`
|
|
402
|
-
**States**: `tl-text-field--error`, `tl-text-field--success`
|
|
403
|
-
|
|
404
|
-
```html
|
|
405
|
-
<!-- Basic text field with external label -->
|
|
406
|
-
<div class="tl-text-field tl-text-field--lg">
|
|
407
|
-
<label class="tl-text-field__label" for="name">Name</label>
|
|
408
|
-
<input
|
|
409
|
-
class="tl-text-field__input"
|
|
410
|
-
id="name"
|
|
411
|
-
type="text"
|
|
412
|
-
placeholder="Enter your name"
|
|
413
|
-
/>
|
|
414
|
-
</div>
|
|
415
|
-
|
|
416
|
-
<!-- Label inside -->
|
|
417
|
-
<div class="tl-text-field tl-text-field--lg tl-text-field--label-inside">
|
|
418
|
-
<label class="tl-text-field__label" for="email">Email</label>
|
|
419
|
-
<input class="tl-text-field__input" id="email" type="email" placeholder=" " />
|
|
420
|
-
</div>
|
|
421
|
-
|
|
422
|
-
<!-- With helper text -->
|
|
423
|
-
<div class="tl-text-field tl-text-field--lg">
|
|
424
|
-
<label class="tl-text-field__label" for="phone">Phone</label>
|
|
425
|
-
<input
|
|
426
|
-
class="tl-text-field__input"
|
|
427
|
-
id="phone"
|
|
428
|
-
type="tel"
|
|
429
|
-
placeholder="+46..."
|
|
430
|
-
/>
|
|
431
|
-
<div class="tl-text-field__bottom">
|
|
432
|
-
<span class="tl-text-field__helper">Include country code</span>
|
|
433
|
-
</div>
|
|
434
|
-
</div>
|
|
435
|
-
|
|
436
|
-
<!-- Error state -->
|
|
437
|
-
<div class="tl-text-field tl-text-field--lg tl-text-field--error">
|
|
438
|
-
<label class="tl-text-field__label" for="req">Required field</label>
|
|
439
|
-
<input class="tl-text-field__input" id="req" type="text" placeholder=" " />
|
|
440
|
-
<div class="tl-text-field__bottom">
|
|
441
|
-
<span class="tl-text-field__helper">This field is required</span>
|
|
442
|
-
</div>
|
|
443
|
-
</div>
|
|
444
|
-
|
|
445
|
-
<!-- With prefix/suffix icons -->
|
|
446
|
-
<div class="tl-text-field tl-text-field--lg">
|
|
447
|
-
<label class="tl-text-field__label" for="search">Search</label>
|
|
448
|
-
<span class="tl-text-field__prefix--icon tl-icon tl-icon--search"></span>
|
|
449
|
-
<input
|
|
450
|
-
class="tl-text-field__input"
|
|
451
|
-
id="search"
|
|
452
|
-
type="text"
|
|
453
|
-
placeholder="Search..."
|
|
454
|
-
/>
|
|
455
|
-
</div>
|
|
456
|
-
|
|
457
|
-
<!-- With character counter -->
|
|
458
|
-
<div class="tl-text-field tl-text-field--lg">
|
|
459
|
-
<label class="tl-text-field__label" for="bio">Bio</label>
|
|
460
|
-
<input
|
|
461
|
-
class="tl-text-field__input"
|
|
462
|
-
id="bio"
|
|
463
|
-
type="text"
|
|
464
|
-
placeholder=" "
|
|
465
|
-
maxlength="100"
|
|
466
|
-
/>
|
|
467
|
-
<div class="tl-text-field__bottom">
|
|
468
|
-
<span class="tl-text-field__helper">Short description</span>
|
|
469
|
-
<span class="tl-text-field__charcounter">
|
|
470
|
-
0<span class="tl-text-field__charcounter-divider">/</span>100
|
|
471
|
-
</span>
|
|
472
|
-
</div>
|
|
473
|
-
</div>
|
|
474
|
-
|
|
475
|
-
<!-- Disabled -->
|
|
476
|
-
<div class="tl-text-field tl-text-field--lg">
|
|
477
|
-
<label class="tl-text-field__label" for="dis">Disabled</label>
|
|
478
|
-
<input
|
|
479
|
-
class="tl-text-field__input"
|
|
480
|
-
id="dis"
|
|
481
|
-
type="text"
|
|
482
|
-
disabled
|
|
483
|
-
placeholder="Cannot edit"
|
|
484
|
-
/>
|
|
485
|
-
</div>
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
**IMPORTANT for label-inside**: The `placeholder` attribute MUST be set (even to `" "` a space) for the floating label animation to work.
|
|
489
|
-
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
## Textarea
|
|
493
|
-
|
|
494
|
-
**Classes**: `tl-textarea`
|
|
495
|
-
**Variants**: `tl-textarea--primary`, `tl-textarea--secondary`, `tl-textarea--label-inside`
|
|
496
|
-
**States**: `tl-textarea--error`, `tl-textarea--success`
|
|
497
|
-
|
|
498
|
-
```html
|
|
499
|
-
<div class="tl-textarea">
|
|
500
|
-
<label class="tl-textarea__label" for="msg">Message</label>
|
|
501
|
-
<textarea
|
|
502
|
-
class="tl-textarea__input"
|
|
503
|
-
id="msg"
|
|
504
|
-
rows="4"
|
|
505
|
-
placeholder="Type here..."
|
|
506
|
-
></textarea>
|
|
507
|
-
<div class="tl-textarea__bottom">
|
|
508
|
-
<span class="tl-textarea__helper">Max 500 characters</span>
|
|
509
|
-
<span class="tl-textarea__charcounter">
|
|
510
|
-
0<span class="tl-textarea__charcounter-divider">/</span>500
|
|
511
|
-
</span>
|
|
512
|
-
</div>
|
|
513
|
-
</div>
|
|
514
|
-
```
|
|
515
|
-
|
|
516
|
-
---
|
|
517
|
-
|
|
518
|
-
## Checkbox
|
|
519
|
-
|
|
520
|
-
**Classes**: `tl-checkbox`
|
|
521
|
-
|
|
522
|
-
```html
|
|
523
|
-
<label class="tl-checkbox">
|
|
524
|
-
<input class="tl-checkbox__input" type="checkbox" />
|
|
525
|
-
<span class="tl-checkbox__label">Accept terms</span>
|
|
526
|
-
</label>
|
|
527
|
-
|
|
528
|
-
<!-- Checked -->
|
|
529
|
-
<label class="tl-checkbox">
|
|
530
|
-
<input class="tl-checkbox__input" type="checkbox" checked />
|
|
531
|
-
<span class="tl-checkbox__label">Selected</span>
|
|
532
|
-
</label>
|
|
533
|
-
|
|
534
|
-
<!-- Disabled -->
|
|
535
|
-
<label class="tl-checkbox">
|
|
536
|
-
<input class="tl-checkbox__input" type="checkbox" disabled />
|
|
537
|
-
<span class="tl-checkbox__label">Disabled</span>
|
|
538
|
-
</label>
|
|
539
|
-
|
|
540
|
-
<!-- Indeterminate (add class manually) -->
|
|
541
|
-
<label class="tl-checkbox">
|
|
542
|
-
<input
|
|
543
|
-
class="tl-checkbox__input tl-checkbox__input--indeterminate"
|
|
544
|
-
type="checkbox"
|
|
545
|
-
/>
|
|
546
|
-
<span class="tl-checkbox__label">Indeterminate</span>
|
|
547
|
-
</label>
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
---
|
|
551
|
-
|
|
552
|
-
## Radio Button
|
|
553
|
-
|
|
554
|
-
**Classes**: `tl-radio-button`
|
|
555
|
-
|
|
556
|
-
```html
|
|
557
|
-
<label class="tl-radio-button">
|
|
558
|
-
<input class="tl-radio-button__input" type="radio" name="group1" value="a" />
|
|
559
|
-
<span class="tl-radio-button__label">Option A</span>
|
|
560
|
-
</label>
|
|
561
|
-
|
|
562
|
-
<label class="tl-radio-button">
|
|
563
|
-
<input class="tl-radio-button__input" type="radio" name="group1" value="b" />
|
|
564
|
-
<span class="tl-radio-button__label">Option B</span>
|
|
565
|
-
</label>
|
|
566
|
-
|
|
567
|
-
<label class="tl-radio-button">
|
|
568
|
-
<input
|
|
569
|
-
class="tl-radio-button__input"
|
|
570
|
-
type="radio"
|
|
571
|
-
name="group1"
|
|
572
|
-
value="c"
|
|
573
|
-
disabled
|
|
574
|
-
/>
|
|
575
|
-
<span class="tl-radio-button__label">Disabled</span>
|
|
576
|
-
</label>
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
---
|
|
580
|
-
|
|
581
|
-
## Toggle / Switch
|
|
582
|
-
|
|
583
|
-
**Classes**: `tl-toggle`
|
|
584
|
-
**Sizes**: default (44×24px), `tl-toggle__input--sm` (28×16px)
|
|
585
|
-
|
|
586
|
-
```html
|
|
587
|
-
<div class="tl-toggle">
|
|
588
|
-
<span class="tl-toggle__headline">Dark mode</span>
|
|
589
|
-
<label>
|
|
590
|
-
<input class="tl-toggle__input" type="checkbox" />
|
|
591
|
-
<span class="tl-toggle__label">Enable</span>
|
|
592
|
-
</label>
|
|
593
|
-
</div>
|
|
594
|
-
|
|
595
|
-
<!-- Small toggle -->
|
|
596
|
-
<div class="tl-toggle">
|
|
597
|
-
<label>
|
|
598
|
-
<input
|
|
599
|
-
class="tl-toggle__input tl-toggle__input--sm"
|
|
600
|
-
type="checkbox"
|
|
601
|
-
checked
|
|
602
|
-
/>
|
|
603
|
-
<span class="tl-toggle__label">On</span>
|
|
604
|
-
</label>
|
|
605
|
-
</div>
|
|
606
|
-
```
|
|
607
|
-
|
|
608
|
-
---
|
|
609
|
-
|
|
610
|
-
## Dropdown / Select
|
|
611
|
-
|
|
612
|
-
**Classes**: `tl-dropdown`
|
|
613
|
-
**Sizes**: default (56px), `tl-dropdown--md` (48px), `tl-dropdown--sm` (40px)
|
|
614
|
-
**Variants**: `tl-dropdown--primary`, `tl-dropdown--secondary`, `tl-dropdown--label-inside`
|
|
615
|
-
**States**: `tl-dropdown--error`
|
|
616
|
-
|
|
617
|
-
### Native Select
|
|
618
|
-
|
|
619
|
-
```html
|
|
620
|
-
<div class="tl-dropdown tl-dropdown--lg">
|
|
621
|
-
<label class="tl-dropdown__label" for="country">Country</label>
|
|
622
|
-
<select class="tl-dropdown__select" id="country">
|
|
623
|
-
<option value="">Select a country</option>
|
|
624
|
-
<option value="se">Sweden</option>
|
|
625
|
-
<option value="no">Norway</option>
|
|
626
|
-
<option value="dk">Denmark</option>
|
|
627
|
-
</select>
|
|
628
|
-
</div>
|
|
629
|
-
```
|
|
630
|
-
|
|
631
|
-
### Custom Dropdown (requires JS for open/close)
|
|
632
|
-
|
|
633
|
-
```html
|
|
634
|
-
<div class="tl-dropdown tl-dropdown--lg">
|
|
635
|
-
<label class="tl-dropdown__label">Status</label>
|
|
636
|
-
<button
|
|
637
|
-
class="tl-dropdown__button"
|
|
638
|
-
aria-expanded="false"
|
|
639
|
-
aria-haspopup="listbox"
|
|
640
|
-
>
|
|
641
|
-
<span class="tl-dropdown__text" data-placeholder="Select status"></span>
|
|
642
|
-
</button>
|
|
643
|
-
<ul class="tl-dropdown__list" role="listbox">
|
|
644
|
-
<li class="tl-dropdown__option" role="option" tabindex="0">Active</li>
|
|
645
|
-
<li class="tl-dropdown__option" role="option" tabindex="0">Inactive</li>
|
|
646
|
-
<li class="tl-dropdown__option tl-dropdown__option--disabled" role="option">
|
|
647
|
-
Archived
|
|
648
|
-
</li>
|
|
649
|
-
</ul>
|
|
650
|
-
</div>
|
|
651
|
-
```
|
|
652
|
-
|
|
653
|
-
### Filterable Dropdown
|
|
654
|
-
|
|
655
|
-
```html
|
|
656
|
-
<div class="tl-dropdown tl-dropdown--lg">
|
|
657
|
-
<label class="tl-dropdown__label">Search items</label>
|
|
658
|
-
<div class="tl-dropdown__input-wrapper">
|
|
659
|
-
<input
|
|
660
|
-
class="tl-dropdown__input"
|
|
661
|
-
type="text"
|
|
662
|
-
placeholder="Type to filter..."
|
|
663
|
-
aria-expanded="false"
|
|
664
|
-
role="combobox"
|
|
665
|
-
autocomplete="off"
|
|
666
|
-
/>
|
|
667
|
-
<button class="tl-dropdown__input-clear" aria-label="Clear">×</button>
|
|
668
|
-
</div>
|
|
669
|
-
<ul class="tl-dropdown__list" role="listbox">
|
|
670
|
-
<li class="tl-dropdown__option" role="option" tabindex="0">Item 1</li>
|
|
671
|
-
<li class="tl-dropdown__option" role="option" tabindex="0">Item 2</li>
|
|
672
|
-
</ul>
|
|
673
|
-
</div>
|
|
674
|
-
```
|
|
675
|
-
|
|
676
|
-
---
|
|
677
|
-
|
|
678
|
-
## Datetime / Date Picker
|
|
679
|
-
|
|
680
|
-
**Classes**: `tl-datetime`
|
|
681
|
-
**Sizes**: default lg (56px), `tl-datetime--md` (48px), `tl-datetime--sm` (40px)
|
|
682
|
-
**Variants**: `tl-datetime--primary`, `tl-datetime--secondary`, `tl-datetime--label-inside`
|
|
683
|
-
**States**: `tl-datetime--error`
|
|
684
|
-
|
|
685
|
-
```html
|
|
686
|
-
<div class="tl-datetime tl-datetime--label-inside">
|
|
687
|
-
<div class="tl-datetime__wrapper">
|
|
688
|
-
<span class="tl-datetime__label-inside">Date</span>
|
|
689
|
-
<input class="tl-datetime__input" type="date" />
|
|
690
|
-
</div>
|
|
691
|
-
</div>
|
|
692
|
-
|
|
693
|
-
<!-- With external label -->
|
|
694
|
-
<div class="tl-datetime">
|
|
695
|
-
<label class="tl-datetime__label" for="start">Start date</label>
|
|
696
|
-
<div class="tl-datetime__wrapper">
|
|
697
|
-
<input class="tl-datetime__input" id="start" type="date" />
|
|
698
|
-
</div>
|
|
699
|
-
</div>
|
|
700
|
-
|
|
701
|
-
<!-- Time picker -->
|
|
702
|
-
<div class="tl-datetime">
|
|
703
|
-
<label class="tl-datetime__label" for="time">Time</label>
|
|
704
|
-
<div class="tl-datetime__wrapper">
|
|
705
|
-
<input class="tl-datetime__input" id="time" type="time" />
|
|
706
|
-
</div>
|
|
707
|
-
</div>
|
|
708
|
-
|
|
709
|
-
<!-- Error state -->
|
|
710
|
-
<div class="tl-datetime tl-datetime--error">
|
|
711
|
-
<label class="tl-datetime__label" for="due">Due date</label>
|
|
712
|
-
<div class="tl-datetime__wrapper">
|
|
713
|
-
<input class="tl-datetime__input" id="due" type="date" />
|
|
714
|
-
</div>
|
|
715
|
-
<span class="tl-datetime__helper">Date cannot be in the past</span>
|
|
716
|
-
</div>
|
|
717
|
-
```
|
|
718
|
-
|
|
719
|
-
---
|
|
720
|
-
|
|
721
|
-
## 03-components-display
|
|
722
|
-
|
|
723
|
-
# Display Components
|
|
724
|
-
|
|
725
|
-
## Card
|
|
726
|
-
|
|
727
|
-
**Classes**: `tl-card`
|
|
728
|
-
**Variants**: `tl-card--primary`, `tl-card--secondary`, `tl-card--clickable`, `tl-card--stretch`, `tl-card--expandable`
|
|
729
|
-
|
|
730
|
-
```html
|
|
731
|
-
<!-- Basic card -->
|
|
732
|
-
<div class="tl-card">
|
|
733
|
-
<div class="tl-card__header">
|
|
734
|
-
<div class="tl-card__headings">
|
|
735
|
-
<span class="tl-card__title">Card Title</span>
|
|
736
|
-
<span class="tl-card__subtitle">Subtitle</span>
|
|
737
|
-
</div>
|
|
738
|
-
</div>
|
|
739
|
-
<div class="tl-card__body">
|
|
740
|
-
<div class="tl-card__content">
|
|
741
|
-
<p>Card content goes here.</p>
|
|
742
|
-
</div>
|
|
743
|
-
</div>
|
|
744
|
-
</div>
|
|
745
|
-
|
|
746
|
-
<!-- Card with image -->
|
|
747
|
-
<div class="tl-card">
|
|
748
|
-
<img class="tl-card__image" src="image.jpg" alt="Description" />
|
|
749
|
-
<div class="tl-card__header tl-card__header--below">
|
|
750
|
-
<div class="tl-card__headings">
|
|
751
|
-
<span class="tl-card__title">Featured Card</span>
|
|
752
|
-
</div>
|
|
753
|
-
</div>
|
|
754
|
-
<div class="tl-card__body">
|
|
755
|
-
<div class="tl-card__content">
|
|
756
|
-
<p>Content below the image.</p>
|
|
757
|
-
</div>
|
|
758
|
-
</div>
|
|
759
|
-
<div class="tl-card__bottom-row">
|
|
760
|
-
<div class="tl-card__actions">
|
|
761
|
-
<button class="tl-button tl-button--primary tl-button--sm">Action</button>
|
|
762
|
-
</div>
|
|
763
|
-
</div>
|
|
764
|
-
</div>
|
|
765
|
-
|
|
766
|
-
<!-- Clickable card -->
|
|
767
|
-
<button class="tl-card tl-card--clickable">
|
|
768
|
-
<div class="tl-card__header">
|
|
769
|
-
<div class="tl-card__headings">
|
|
770
|
-
<span class="tl-card__title">Clickable</span>
|
|
771
|
-
</div>
|
|
772
|
-
</div>
|
|
773
|
-
<div class="tl-card__body">
|
|
774
|
-
<div class="tl-card__content">Click anywhere</div>
|
|
775
|
-
</div>
|
|
776
|
-
</button>
|
|
777
|
-
|
|
778
|
-
<!-- Card with thumbnail -->
|
|
779
|
-
<div class="tl-card">
|
|
780
|
-
<div class="tl-card__header">
|
|
781
|
-
<img class="tl-card__thumbnail" src="avatar.jpg" alt="User" />
|
|
782
|
-
<div class="tl-card__headings">
|
|
783
|
-
<span class="tl-card__title">User Name</span>
|
|
784
|
-
<span class="tl-card__subtitle">Role</span>
|
|
785
|
-
</div>
|
|
786
|
-
</div>
|
|
787
|
-
</div>
|
|
788
|
-
```
|
|
789
|
-
|
|
790
|
-
---
|
|
791
|
-
|
|
792
|
-
## Accordion
|
|
793
|
-
|
|
794
|
-
**Classes**: `tl-accordion`
|
|
795
|
-
**Variants**: `tl-accordion--primary`, `tl-accordion--secondary`, `tl-accordion--hide-last-border`
|
|
796
|
-
|
|
797
|
-
```html
|
|
798
|
-
<div class="tl-accordion">
|
|
799
|
-
<!-- Expanded item -->
|
|
800
|
-
<div class="tl-accordion__item tl-accordion__item--expanded">
|
|
801
|
-
<button class="tl-accordion__header-icon-end" aria-expanded="true">
|
|
802
|
-
<span class="tl-accordion__title">Section 1</span>
|
|
803
|
-
</button>
|
|
804
|
-
<div class="tl-accordion__panel">
|
|
805
|
-
<p>Content of section 1.</p>
|
|
806
|
-
</div>
|
|
807
|
-
</div>
|
|
808
|
-
|
|
809
|
-
<!-- Collapsed item -->
|
|
810
|
-
<div class="tl-accordion__item">
|
|
811
|
-
<button class="tl-accordion__header-icon-end" aria-expanded="false">
|
|
812
|
-
<span class="tl-accordion__title">Section 2</span>
|
|
813
|
-
</button>
|
|
814
|
-
<div class="tl-accordion__panel">
|
|
815
|
-
<p>Content of section 2.</p>
|
|
816
|
-
</div>
|
|
817
|
-
</div>
|
|
818
|
-
|
|
819
|
-
<!-- Disabled item -->
|
|
820
|
-
<div class="tl-accordion__item tl-accordion__item--disabled">
|
|
821
|
-
<button
|
|
822
|
-
class="tl-accordion__header-icon-end"
|
|
823
|
-
aria-expanded="false"
|
|
824
|
-
disabled
|
|
825
|
-
>
|
|
826
|
-
<span class="tl-accordion__title">Disabled</span>
|
|
827
|
-
</button>
|
|
828
|
-
<div class="tl-accordion__panel">
|
|
829
|
-
<p>Cannot expand.</p>
|
|
830
|
-
</div>
|
|
831
|
-
</div>
|
|
832
|
-
</div>
|
|
833
|
-
```
|
|
834
|
-
|
|
835
|
-
**Icon position**: Use `tl-accordion__header-icon-start` for chevron on left, `tl-accordion__header-icon-end` for right.
|
|
836
|
-
|
|
837
|
-
---
|
|
838
|
-
|
|
839
|
-
## Badge
|
|
840
|
-
|
|
841
|
-
**Classes**: `tl-badge`
|
|
842
|
-
**Sizes**: `tl-badge--sm` (8×8px dot), `tl-badge--lg` (20×20px), `tl-badge--pill` (auto-width)
|
|
843
|
-
|
|
844
|
-
**IMPORTANT**: The badge component does NOT have built-in status variants (success, warning, danger). It only provides neutral notification badges.
|
|
845
|
-
|
|
846
|
-
```html
|
|
847
|
-
<!-- Notification badges (default usage) -->
|
|
848
|
-
<span class="tl-badge tl-badge--sm"></span>
|
|
849
|
-
<span class="tl-badge tl-badge--lg"><span class="tl-badge__text">5</span></span>
|
|
850
|
-
<span class="tl-badge tl-badge--pill"
|
|
851
|
-
><span class="tl-badge__text">New</span></span
|
|
852
|
-
>
|
|
853
|
-
```
|
|
854
|
-
|
|
855
|
-
### Status Badges (Custom Component)
|
|
856
|
-
|
|
857
|
-
**NEVER use inline styles on badges.** For status indicators (success, warning, danger), create a custom component with proper CSS classes:
|
|
858
|
-
|
|
859
|
-
```css
|
|
860
|
-
/* Add to your custom stylesheet */
|
|
861
|
-
.status-badge {
|
|
862
|
-
display: inline-block;
|
|
863
|
-
padding: var(--dimension-space-tiny) var(--dimension-space-small);
|
|
864
|
-
border-radius: var(--dimension-radius-rounded);
|
|
865
|
-
font-size: 12px;
|
|
866
|
-
font-weight: var(--scania-font-weight-bold);
|
|
867
|
-
text-align: center;
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
.status-badge--success {
|
|
871
|
-
background-color: var(--color-system-success-discrete);
|
|
872
|
-
color: var(--color-system-success-default);
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
.status-badge--warning {
|
|
876
|
-
background-color: var(--color-system-warning-discrete);
|
|
877
|
-
color: var(--color-system-warning-default);
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
.status-badge--danger {
|
|
881
|
-
background-color: var(--color-system-danger-discrete);
|
|
882
|
-
color: var(--color-system-danger-default);
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
.status-badge--info {
|
|
886
|
-
background-color: var(--color-system-info-discrete);
|
|
887
|
-
color: var(--color-system-info-default);
|
|
888
|
-
}
|
|
889
|
-
```
|
|
890
|
-
|
|
891
|
-
```html
|
|
892
|
-
<!-- CUSTOM: Status badges using Tegel tokens -->
|
|
893
|
-
<span class="status-badge status-badge--success">Active</span>
|
|
894
|
-
<span class="status-badge status-badge--warning">Pending</span>
|
|
895
|
-
<span class="status-badge status-badge--danger">Error</span>
|
|
896
|
-
<span class="status-badge status-badge--info">Info</span>
|
|
897
|
-
```
|
|
898
|
-
|
|
899
|
-
---
|
|
900
|
-
|
|
901
|
-
## Banner
|
|
902
|
-
|
|
903
|
-
**Classes**: `tl-banner`
|
|
904
|
-
**Variants**: `tl-banner--error`, `tl-banner--information`
|
|
905
|
-
|
|
906
|
-
```html
|
|
907
|
-
<!-- Default banner -->
|
|
908
|
-
<div class="tl-banner" role="alert">
|
|
909
|
-
<span class="tl-banner__icon">
|
|
910
|
-
<span class="tl-icon tl-icon--info"></span>
|
|
911
|
-
</span>
|
|
912
|
-
<div class="tl-banner__content">
|
|
913
|
-
<div class="tl-banner__text">
|
|
914
|
-
<h6 class="tl-banner__header">Notice</h6>
|
|
915
|
-
<p class="tl-banner__subheader">System maintenance scheduled.</p>
|
|
916
|
-
</div>
|
|
917
|
-
<div class="tl-banner__actions">
|
|
918
|
-
<a href="#" class="tl-link tl-link--underline">Learn more</a>
|
|
919
|
-
</div>
|
|
920
|
-
</div>
|
|
921
|
-
<button class="tl-banner__close" aria-label="Close">
|
|
922
|
-
<span class="tl-icon tl-icon--cross"></span>
|
|
923
|
-
</button>
|
|
924
|
-
</div>
|
|
925
|
-
|
|
926
|
-
<!-- Error banner -->
|
|
927
|
-
<div class="tl-banner tl-banner--error" role="alert">
|
|
928
|
-
<span class="tl-banner__icon">
|
|
929
|
-
<span class="tl-icon tl-icon--error"></span>
|
|
930
|
-
</span>
|
|
931
|
-
<div class="tl-banner__content">
|
|
932
|
-
<div class="tl-banner__text">
|
|
933
|
-
<h6 class="tl-banner__header">Error</h6>
|
|
934
|
-
<p class="tl-banner__subheader">Something went wrong.</p>
|
|
935
|
-
</div>
|
|
936
|
-
</div>
|
|
937
|
-
</div>
|
|
938
|
-
```
|
|
939
|
-
|
|
940
|
-
---
|
|
941
|
-
|
|
942
|
-
## Message
|
|
943
|
-
|
|
944
|
-
**Classes**: `tl-message`
|
|
945
|
-
**Variants**: `tl-message--information`, `tl-message--success`, `tl-message--warning`, `tl-message--error`, `tl-message--minimal`
|
|
946
|
-
**Mode**: `tl-message--primary`, `tl-message--secondary`, `tl-message--no-icon`
|
|
947
|
-
|
|
948
|
-
```html
|
|
949
|
-
<!-- Information message -->
|
|
950
|
-
<div class="tl-message tl-message--information">
|
|
951
|
-
<div class="tl-message__wrapper">
|
|
952
|
-
<div class="tl-message__content">
|
|
953
|
-
<p class="tl-message__header">Information</p>
|
|
954
|
-
<p class="tl-message__extended-message">Here is some helpful context.</p>
|
|
955
|
-
</div>
|
|
956
|
-
</div>
|
|
957
|
-
</div>
|
|
958
|
-
|
|
959
|
-
<!-- Error message -->
|
|
960
|
-
<div class="tl-message tl-message--error">
|
|
961
|
-
<div class="tl-message__wrapper">
|
|
962
|
-
<div class="tl-message__content">
|
|
963
|
-
<p class="tl-message__header">Error occurred</p>
|
|
964
|
-
<p class="tl-message__extended-message">Please try again later.</p>
|
|
965
|
-
</div>
|
|
966
|
-
</div>
|
|
967
|
-
</div>
|
|
968
|
-
|
|
969
|
-
<!-- Minimal (inline) error message -->
|
|
970
|
-
<div class="tl-message tl-message--error tl-message--minimal">
|
|
971
|
-
<div class="tl-message__wrapper">
|
|
972
|
-
<div class="tl-message__content">
|
|
973
|
-
<p class="tl-message__header">Invalid input</p>
|
|
974
|
-
</div>
|
|
975
|
-
</div>
|
|
976
|
-
</div>
|
|
977
|
-
```
|
|
978
|
-
|
|
979
|
-
---
|
|
980
|
-
|
|
981
|
-
## Toast
|
|
982
|
-
|
|
983
|
-
**Classes**: `tl-toast`
|
|
984
|
-
**Variants**: `tl-toast--information`, `tl-toast--success`, `tl-toast--error`, `tl-toast--warning`
|
|
985
|
-
|
|
986
|
-
```html
|
|
987
|
-
<div class="tl-toast tl-toast--success" role="alert">
|
|
988
|
-
<span class="tl-toast__icon">
|
|
989
|
-
<span class="tl-icon tl-icon--tick"></span>
|
|
990
|
-
</span>
|
|
991
|
-
<div class="tl-toast__content">
|
|
992
|
-
<div class="tl-toast__text">
|
|
993
|
-
<h6 class="tl-toast__header">Success</h6>
|
|
994
|
-
<p class="tl-toast__subheader">Item was saved.</p>
|
|
995
|
-
</div>
|
|
996
|
-
</div>
|
|
997
|
-
<button class="tl-toast__close" aria-label="Dismiss">
|
|
998
|
-
<span class="tl-icon tl-icon--cross"></span>
|
|
999
|
-
</button>
|
|
1000
|
-
</div>
|
|
1001
|
-
```
|
|
1002
|
-
|
|
1003
|
-
Width is fixed at `348px`. Position with CSS `position: fixed`.
|
|
1004
|
-
|
|
1005
|
-
---
|
|
1006
|
-
|
|
1007
|
-
## Modal / Dialog
|
|
1008
|
-
|
|
1009
|
-
**Classes**: `tl-modal`
|
|
1010
|
-
**Sizes**: `tl-modal--xs`, `tl-modal--sm`, `tl-modal--md`, `tl-modal--lg`
|
|
1011
|
-
**Modifiers**: `tl-modal--visible` (shows modal), `tl-modal--sticky` (sticky header/actions)
|
|
1012
|
-
|
|
1013
|
-
```html
|
|
1014
|
-
<!-- Overlay (backdrop) -->
|
|
1015
|
-
<div class="tl-modal__overlay tl-modal--visible"></div>
|
|
1016
|
-
|
|
1017
|
-
<!-- Modal -->
|
|
1018
|
-
<div
|
|
1019
|
-
class="tl-modal tl-modal--sm tl-modal--visible tl-modal--sticky"
|
|
1020
|
-
role="dialog"
|
|
1021
|
-
aria-modal="true"
|
|
1022
|
-
aria-labelledby="modal-title"
|
|
1023
|
-
>
|
|
1024
|
-
<div class="tl-modal__header">
|
|
1025
|
-
<h5 class="tl-modal__title" id="modal-title">Confirm Action</h5>
|
|
1026
|
-
<button class="tl-modal__close" aria-label="Close">
|
|
1027
|
-
<span class="tl-icon tl-icon--cross"></span>
|
|
1028
|
-
</button>
|
|
1029
|
-
</div>
|
|
1030
|
-
<div class="tl-modal__body">
|
|
1031
|
-
<p>Are you sure you want to proceed?</p>
|
|
1032
|
-
</div>
|
|
1033
|
-
<div class="tl-modal__actions">
|
|
1034
|
-
<button class="tl-button tl-button--secondary tl-button--md">Cancel</button>
|
|
1035
|
-
<button class="tl-button tl-button--primary tl-button--md">Confirm</button>
|
|
1036
|
-
</div>
|
|
1037
|
-
</div>
|
|
1038
|
-
```
|
|
1039
|
-
|
|
1040
|
-
**Responsive widths** for `tl-modal--sm`:
|
|
1041
|
-
|
|
1042
|
-
- Mobile (320px): 100%
|
|
1043
|
-
- Tablet (672px): 62.5%
|
|
1044
|
-
- Desktop (1056px): 43.75%
|
|
1045
|
-
- Wide (1312px): 37.5%
|
|
1046
|
-
- Ultra-wide (1584px): 37.5%
|
|
1047
|
-
|
|
1048
|
-
---
|
|
1049
|
-
|
|
1050
|
-
## Table
|
|
1051
|
-
|
|
1052
|
-
**Classes**: `tl-table`
|
|
1053
|
-
**Variants**: `tl-table--primary`, `tl-table--secondary`, `tl-table--responsive`, `tl-table--compact`
|
|
1054
|
-
**Modifiers**: `tl-table--zebra-rows-odd`, `tl-table--zebra-rows-even`, `tl-table--vertical-dividers`, `tl-table--horizontal-scroll`, `tl-table--clickable`
|
|
1055
|
-
|
|
1056
|
-
```html
|
|
1057
|
-
<table class="tl-table tl-table--responsive">
|
|
1058
|
-
<!-- Optional toolbar -->
|
|
1059
|
-
<caption class="tl-table__toolbar">
|
|
1060
|
-
<div class="tl-table__upper-bar">
|
|
1061
|
-
<div class="tl-table__actionbar-left">
|
|
1062
|
-
<span class="tl-table__title">Users</span>
|
|
1063
|
-
</div>
|
|
1064
|
-
</div>
|
|
1065
|
-
</caption>
|
|
1066
|
-
|
|
1067
|
-
<thead class="tl-table__header">
|
|
1068
|
-
<tr class="tl-table__row">
|
|
1069
|
-
<th class="tl-table__header-cell">Name</th>
|
|
1070
|
-
<th class="tl-table__header-cell">Email</th>
|
|
1071
|
-
<th class="tl-table__header-cell">Role</th>
|
|
1072
|
-
</tr>
|
|
1073
|
-
</thead>
|
|
1074
|
-
|
|
1075
|
-
<tbody class="tl-table__body">
|
|
1076
|
-
<tr class="tl-table__row">
|
|
1077
|
-
<td class="tl-table__body-cell">John Doe</td>
|
|
1078
|
-
<td class="tl-table__body-cell">john@example.com</td>
|
|
1079
|
-
<td class="tl-table__body-cell">Admin</td>
|
|
1080
|
-
</tr>
|
|
1081
|
-
<tr class="tl-table__row">
|
|
1082
|
-
<td class="tl-table__body-cell">Jane Smith</td>
|
|
1083
|
-
<td class="tl-table__body-cell">jane@example.com</td>
|
|
1084
|
-
<td class="tl-table__body-cell">User</td>
|
|
1085
|
-
</tr>
|
|
1086
|
-
</tbody>
|
|
1087
|
-
</table>
|
|
1088
|
-
```
|
|
1089
|
-
|
|
1090
|
-
### Sortable Headers
|
|
1091
|
-
|
|
1092
|
-
```html
|
|
1093
|
-
<th class="tl-table__header-cell tl-table__header-cell--sortable">
|
|
1094
|
-
<button class="tl-table__header-button">
|
|
1095
|
-
<span class="tl-table__header-button-text">Name</span>
|
|
1096
|
-
<span class="tl-table__header-button-icon tl-icon tl-icon--sorting"></span>
|
|
1097
|
-
</button>
|
|
1098
|
-
</th>
|
|
1099
|
-
```
|
|
1100
|
-
|
|
1101
|
-
---
|
|
1102
|
-
|
|
1103
|
-
## Block (Content Section)
|
|
1104
|
-
|
|
1105
|
-
**Classes**: `tl-block`
|
|
1106
|
-
**Variants**: `tl-block--primary`, `tl-block--secondary`
|
|
1107
|
-
|
|
1108
|
-
```html
|
|
1109
|
-
<div class="tl-block tl-block--primary">
|
|
1110
|
-
<h2>Section Title</h2>
|
|
1111
|
-
<p>Body text in a block.</p>
|
|
1112
|
-
<div class="tl-block">
|
|
1113
|
-
<h3>Nested Block</h3>
|
|
1114
|
-
<p>Nested content with alternating background.</p>
|
|
1115
|
-
</div>
|
|
1116
|
-
</div>
|
|
1117
|
-
```
|
|
1118
|
-
|
|
1119
|
-
Blocks alternate background colors automatically when nested.
|
|
1120
|
-
|
|
1121
|
-
---
|
|
1122
|
-
|
|
1123
|
-
## Stepper
|
|
1124
|
-
|
|
1125
|
-
**Classes**: `tl-stepper`
|
|
1126
|
-
**Sizes**: `tl-stepper--lg`, `tl-stepper--sm`
|
|
1127
|
-
**Direction**: `tl-stepper--horizontal`, `tl-stepper--vertical`
|
|
1128
|
-
**Label**: `tl-stepper--label-below`, `tl-stepper--label-aside`, `tl-stepper--hide-labels`
|
|
1129
|
-
|
|
1130
|
-
```html
|
|
1131
|
-
<div class="tl-stepper tl-stepper--horizontal tl-stepper--lg">
|
|
1132
|
-
<ol class="tl-stepper__list">
|
|
1133
|
-
<li class="tl-stepper__step tl-stepper__step--success">
|
|
1134
|
-
<span class="tl-stepper__node"></span>
|
|
1135
|
-
<span class="tl-stepper__label">Step 1</span>
|
|
1136
|
-
</li>
|
|
1137
|
-
<li class="tl-stepper__step tl-stepper__step--current">
|
|
1138
|
-
<span class="tl-stepper__node">2</span>
|
|
1139
|
-
<span class="tl-stepper__label">Step 2</span>
|
|
1140
|
-
</li>
|
|
1141
|
-
<li class="tl-stepper__step tl-stepper__step--upcoming">
|
|
1142
|
-
<span class="tl-stepper__node">3</span>
|
|
1143
|
-
<span class="tl-stepper__label">Step 3</span>
|
|
1144
|
-
</li>
|
|
1145
|
-
</ol>
|
|
1146
|
-
</div>
|
|
1147
|
-
```
|
|
1148
|
-
|
|
1149
|
-
Step states: `tl-stepper__step--success`, `tl-stepper__step--error`, `tl-stepper__step--current`, `tl-stepper__step--upcoming`
|
|
1150
|
-
|
|
1151
|
-
---
|
|
1152
|
-
|
|
1153
|
-
## Spinner / Loader
|
|
1154
|
-
|
|
1155
|
-
**Classes**: `tl-spinner`
|
|
1156
|
-
**Sizes**: `tl-spinner--xs` (16px), `tl-spinner--sm` (24px), `tl-spinner--md` (52px), `tl-spinner--lg` (84px)
|
|
1157
|
-
**Color**: `tl-spinner--default`, `tl-spinner--inverted`
|
|
1158
|
-
|
|
1159
|
-
```html
|
|
1160
|
-
<svg
|
|
1161
|
-
class="tl-spinner tl-spinner--md tl-spinner--default"
|
|
1162
|
-
aria-label="Loading"
|
|
1163
|
-
role="img"
|
|
1164
|
-
>
|
|
1165
|
-
<circle class="tl-spinner__circle"></circle>
|
|
1166
|
-
</svg>
|
|
1167
|
-
```
|
|
1168
|
-
|
|
1169
|
-
---
|
|
1170
|
-
|
|
1171
|
-
## Popover Canvas
|
|
1172
|
-
|
|
1173
|
-
**Classes**: `tl-popover-canvas`
|
|
1174
|
-
**Modifiers**: `tl-popover-canvas--visible`, `tl-popover-canvas--animation-fade`, `tl-popover-canvas--primary`, `tl-popover-canvas--secondary`
|
|
1175
|
-
|
|
1176
|
-
```html
|
|
1177
|
-
<div
|
|
1178
|
-
class="tl-popover-canvas tl-popover-canvas--visible tl-popover-canvas--animation-fade"
|
|
1179
|
-
>
|
|
1180
|
-
<div class="tl-popover-canvas__content">
|
|
1181
|
-
<h5 class="tl-popover-canvas__header">Popover Title</h5>
|
|
1182
|
-
<p>Content here.</p>
|
|
1183
|
-
<div class="tl-popover-canvas__actions">
|
|
1184
|
-
<button class="tl-button tl-button--ghost tl-button--sm">Cancel</button>
|
|
1185
|
-
<button class="tl-button tl-button--primary tl-button--sm">
|
|
1186
|
-
Confirm
|
|
1187
|
-
</button>
|
|
1188
|
-
</div>
|
|
1189
|
-
</div>
|
|
1190
|
-
</div>
|
|
1191
|
-
```
|
|
1192
|
-
|
|
1193
|
-
---
|
|
1194
|
-
|
|
1195
|
-
## 04-components-navigation
|
|
1196
|
-
|
|
1197
|
-
# Navigation & Utility Components
|
|
1198
|
-
|
|
1199
|
-
## Breadcrumbs
|
|
1200
|
-
|
|
1201
|
-
**Classes**: `tl-breadcrumbs`
|
|
1202
|
-
|
|
1203
|
-
```html
|
|
1204
|
-
<nav class="tl-breadcrumbs" aria-label="Breadcrumb">
|
|
1205
|
-
<ol>
|
|
1206
|
-
<li><a href="/">Home</a></li>
|
|
1207
|
-
<li><a href="/products">Products</a></li>
|
|
1208
|
-
<li><a href="/products/trucks" aria-current="page">Trucks</a></li>
|
|
1209
|
-
</ol>
|
|
1210
|
-
</nav>
|
|
1211
|
-
```
|
|
1212
|
-
|
|
1213
|
-
---
|
|
1214
|
-
|
|
1215
|
-
## Chip
|
|
1216
|
-
|
|
1217
|
-
**Classes**: `tl-chip`
|
|
1218
|
-
**Sizes**: `tl-chip--sm` (24px), `tl-chip--lg` (32px)
|
|
1219
|
-
**States**: `tl-chip--selected`
|
|
1220
|
-
**Modifiers**: `tl-chip--prefix`, `tl-chip--suffix`
|
|
1221
|
-
|
|
1222
|
-
```html
|
|
1223
|
-
<button class="tl-chip tl-chip--lg">Default</button>
|
|
1224
|
-
<button class="tl-chip tl-chip--lg tl-chip--selected">Selected</button>
|
|
1225
|
-
<button class="tl-chip tl-chip--sm" disabled>Disabled</button>
|
|
1226
|
-
```
|
|
1227
|
-
|
|
1228
|
-
---
|
|
1229
|
-
|
|
1230
|
-
## Tabs
|
|
1231
|
-
|
|
1232
|
-
### Inline Tabs
|
|
1233
|
-
|
|
1234
|
-
```html
|
|
1235
|
-
<div class="tl-inline-tabs" role="tablist">
|
|
1236
|
-
<button
|
|
1237
|
-
class="tl-inline-tabs__tab tl-inline-tabs__tab--selected"
|
|
1238
|
-
role="tab"
|
|
1239
|
-
aria-selected="true"
|
|
1240
|
-
>
|
|
1241
|
-
Tab 1
|
|
1242
|
-
</button>
|
|
1243
|
-
<button class="tl-inline-tabs__tab" role="tab" aria-selected="false">
|
|
1244
|
-
Tab 2
|
|
1245
|
-
</button>
|
|
1246
|
-
<button
|
|
1247
|
-
class="tl-inline-tabs__tab tl-inline-tabs__tab--disabled"
|
|
1248
|
-
role="tab"
|
|
1249
|
-
aria-disabled="true"
|
|
1250
|
-
>
|
|
1251
|
-
Disabled
|
|
1252
|
-
</button>
|
|
1253
|
-
</div>
|
|
1254
|
-
```
|
|
1255
|
-
|
|
1256
|
-
### Folder Tabs
|
|
1257
|
-
|
|
1258
|
-
```html
|
|
1259
|
-
<div class="tl-folder-tabs" role="tablist">
|
|
1260
|
-
<button
|
|
1261
|
-
class="tl-folder-tabs__tab tl-folder-tabs__tab--selected"
|
|
1262
|
-
role="tab"
|
|
1263
|
-
aria-selected="true"
|
|
1264
|
-
>
|
|
1265
|
-
Active
|
|
1266
|
-
</button>
|
|
1267
|
-
<button class="tl-folder-tabs__tab" role="tab" aria-selected="false">
|
|
1268
|
-
Another
|
|
1269
|
-
</button>
|
|
1270
|
-
</div>
|
|
1271
|
-
```
|
|
1272
|
-
|
|
1273
|
-
### Navigation Tabs
|
|
1274
|
-
|
|
1275
|
-
```html
|
|
1276
|
-
<nav class="tl-navigation-tabs" role="tablist">
|
|
1277
|
-
<a
|
|
1278
|
-
class="tl-navigation-tabs__tab tl-navigation-tabs__tab--selected"
|
|
1279
|
-
href="/overview"
|
|
1280
|
-
role="tab"
|
|
1281
|
-
aria-selected="true"
|
|
1282
|
-
>Overview</a
|
|
1283
|
-
>
|
|
1284
|
-
<a class="tl-navigation-tabs__tab" href="/details" role="tab">Details</a>
|
|
1285
|
-
</nav>
|
|
1286
|
-
```
|
|
1287
|
-
|
|
1288
|
-
---
|
|
1289
|
-
|
|
1290
|
-
## Link
|
|
1291
|
-
|
|
1292
|
-
**Classes**: `tl-link`
|
|
1293
|
-
**Modifiers**: `tl-link--underline`, `tl-link--standalone`, `tl-link--disabled`
|
|
1294
|
-
|
|
1295
|
-
```html
|
|
1296
|
-
<a href="/page" class="tl-link tl-link--underline">
|
|
1297
|
-
Learn more
|
|
1298
|
-
<span class="tl-link__icon"
|
|
1299
|
-
><span class="tl-icon tl-icon--arrow_right"></span
|
|
1300
|
-
></span>
|
|
1301
|
-
</a>
|
|
1302
|
-
|
|
1303
|
-
<!-- Standalone link (inherits detail-02 typography) -->
|
|
1304
|
-
<a href="/page" class="tl-link tl-link--standalone tl-link--underline"
|
|
1305
|
-
>Standalone Link</a
|
|
1306
|
-
>
|
|
1307
|
-
|
|
1308
|
-
<!-- Disabled link -->
|
|
1309
|
-
<span class="tl-link tl-link--disabled">Disabled link</span>
|
|
1310
|
-
```
|
|
1311
|
-
|
|
1312
|
-
---
|
|
1313
|
-
|
|
1314
|
-
## Divider
|
|
1315
|
-
|
|
1316
|
-
**Classes**: `tl-divider`
|
|
1317
|
-
**Variants**: `tl-divider--horizontal`, `tl-divider--vertical`, `tl-divider--expressive`, `tl-divider--discrete`
|
|
1318
|
-
|
|
1319
|
-
```html
|
|
1320
|
-
<div class="tl-divider tl-divider--horizontal"></div>
|
|
1321
|
-
<div class="tl-divider tl-divider--vertical" style="height: 40px;"></div>
|
|
1322
|
-
```
|
|
1323
|
-
|
|
1324
|
-
---
|
|
1325
|
-
|
|
1326
|
-
## Tooltip
|
|
1327
|
-
|
|
1328
|
-
**Classes**: `tl-tooltip`
|
|
1329
|
-
**Modifiers**: `tl-tooltip--visible`, position variants: `tl-tooltip--top-start`, `tl-tooltip--top-end`, `tl-tooltip--bottom-start`, `tl-tooltip--bottom-end`, `tl-tooltip--left-start`, `tl-tooltip--left-end`, `tl-tooltip--right-start`, `tl-tooltip--right-end`
|
|
1330
|
-
|
|
1331
|
-
```html
|
|
1332
|
-
<div class="tl-tooltip tl-tooltip--visible tl-tooltip--bottom-start">
|
|
1333
|
-
Tooltip text here
|
|
1334
|
-
</div>
|
|
1335
|
-
```
|
|
1336
|
-
|
|
1337
|
-
Max width: 204px. Positioning requires JS or CSS `position: fixed`.
|
|
1338
|
-
|
|
1339
|
-
---
|
|
1340
|
-
|
|
1341
|
-
## Popover Menu
|
|
1342
|
-
|
|
1343
|
-
**Classes**: `tl-popover-menu`
|
|
1344
|
-
**Variants**: `tl-popover-menu--primary`, `tl-popover-menu--secondary`, `tl-popover-menu--visible`, `tl-popover-menu--fluid`
|
|
1345
|
-
|
|
1346
|
-
```html
|
|
1347
|
-
<div
|
|
1348
|
-
class="tl-popover-menu tl-popover-menu--visible tl-popover-menu--animation-fade"
|
|
1349
|
-
>
|
|
1350
|
-
<div class="tl-popover-menu__item-wrapper">
|
|
1351
|
-
<button class="tl-popover-menu__item">
|
|
1352
|
-
<span class="tl-icon tl-icon--edit"></span>
|
|
1353
|
-
Edit
|
|
1354
|
-
</button>
|
|
1355
|
-
<button class="tl-popover-menu__item">
|
|
1356
|
-
<span class="tl-icon tl-icon--copy"></span>
|
|
1357
|
-
Duplicate
|
|
1358
|
-
</button>
|
|
1359
|
-
<div class="tl-divider tl-divider--horizontal"></div>
|
|
1360
|
-
<button class="tl-popover-menu__item--disabled">
|
|
1361
|
-
<span class="tl-icon tl-icon--trash"></span>
|
|
1362
|
-
Delete
|
|
1363
|
-
</button>
|
|
1364
|
-
</div>
|
|
1365
|
-
</div>
|
|
1366
|
-
```
|
|
1367
|
-
|
|
1368
|
-
---
|
|
1369
|
-
|
|
1370
|
-
## Slider
|
|
1371
|
-
|
|
1372
|
-
**Classes**: `tl-slider`
|
|
1373
|
-
**Sizes**: default, `tl-slider--small`
|
|
1374
|
-
|
|
1375
|
-
Slider requires JavaScript for thumb positioning. CSS provides the visual styling only.
|
|
1376
|
-
|
|
1377
|
-
---
|
|
1378
|
-
|
|
1379
|
-
## Icon
|
|
1380
|
-
|
|
1381
|
-
**Classes**: `tl-icon tl-icon--{name}`
|
|
1382
|
-
**Sizes**: `tl-icon--12` through `tl-icon--96` (even numbers only)
|
|
1383
|
-
|
|
1384
|
-
Common icons:
|
|
1385
|
-
|
|
1386
|
-
- Navigation: `arrow_left`, `arrow_right`, `arrow_up`, `arrow_down`, `chevron_down`, `chevron_up`, `chevron_left`, `chevron_right`, `back`
|
|
1387
|
-
- Actions: `edit`, `trash`, `copy`, `save`, `download`, `upload`, `export`, `search`, `filters`, `settings`, `plus`, `minus`, `cross`, `tick`
|
|
1388
|
-
- Status: `error`, `warning`, `info`, `tick`
|
|
1389
|
-
- UI: `burger`, `bento`, `kebab`, `meatballs`, `eye`, `eye_inactive`, `lock`, `unlock`
|
|
1390
|
-
- Objects: `calendar`, `clock`, `document`, `folder`, `image`, `profile`, `home`, `notification`
|
|
1391
|
-
|
|
1392
|
-
```html
|
|
1393
|
-
<span class="tl-icon tl-icon--search"></span>
|
|
1394
|
-
<span class="tl-icon tl-icon--search tl-icon--24"></span>
|
|
1395
|
-
<span class="tl-icon tl-icon--error tl-icon--16"></span>
|
|
1396
|
-
```
|
|
1397
|
-
|
|
1398
|
-
Icons inherit `color` from parent via `currentcolor`.
|
|
1399
|
-
|
|
1400
|
-
---
|
|
1401
|
-
|
|
1402
|
-
## Header
|
|
1403
|
-
|
|
1404
|
-
**Classes**: `tl-header`
|
|
1405
|
-
|
|
1406
|
-
```html
|
|
1407
|
-
<header class="tl-header">
|
|
1408
|
-
<nav class="tl-header__nav">
|
|
1409
|
-
<ul class="tl-header__list">
|
|
1410
|
-
<!-- Brand logo -->
|
|
1411
|
-
<li class="tl-header__item">
|
|
1412
|
-
<a class="tl-header__item-wrapper" href="/">
|
|
1413
|
-
<span class="tl-header__brand"></span>
|
|
1414
|
-
</a>
|
|
1415
|
-
</li>
|
|
1416
|
-
|
|
1417
|
-
<!-- Title -->
|
|
1418
|
-
<li class="tl-header__item">
|
|
1419
|
-
<div class="tl-header__title">
|
|
1420
|
-
<span class="tl-header__title-text">Application Name</span>
|
|
1421
|
-
</div>
|
|
1422
|
-
</li>
|
|
1423
|
-
|
|
1424
|
-
<!-- Nav items -->
|
|
1425
|
-
<li class="tl-header__item">
|
|
1426
|
-
<a class="tl-header__item-wrapper" href="/dashboard">Dashboard</a>
|
|
1427
|
-
</li>
|
|
1428
|
-
|
|
1429
|
-
<!-- Spacer -->
|
|
1430
|
-
<li class="tl-header__middle-spacer"></li>
|
|
1431
|
-
|
|
1432
|
-
<!-- Dropdown -->
|
|
1433
|
-
<li class="tl-header__dropdown">
|
|
1434
|
-
<button class="tl-header__dropdown-wrapper" aria-expanded="false">
|
|
1435
|
-
<span class="tl-icon tl-icon--profile"></span>
|
|
1436
|
-
</button>
|
|
1437
|
-
<ul class="tl-header__dropdown-menu">
|
|
1438
|
-
<li class="tl-header__dropdown-menu-item">
|
|
1439
|
-
<a href="/settings">Settings</a>
|
|
1440
|
-
</li>
|
|
1441
|
-
<li class="tl-header__dropdown-menu-item">
|
|
1442
|
-
<button>Logout</button>
|
|
1443
|
-
</li>
|
|
1444
|
-
</ul>
|
|
1445
|
-
</li>
|
|
1446
|
-
</ul>
|
|
1447
|
-
</nav>
|
|
1448
|
-
</header>
|
|
1449
|
-
```
|
|
1450
|
-
|
|
1451
|
-
---
|
|
1452
|
-
|
|
1453
|
-
## Footer
|
|
1454
|
-
|
|
1455
|
-
**Classes**: `tl-footer`
|
|
1456
|
-
**Variants**: `tl-footer--primary`, `tl-footer--secondary`
|
|
1457
|
-
|
|
1458
|
-
```html
|
|
1459
|
-
<footer class="tl-footer">
|
|
1460
|
-
<!-- Top section with link groups -->
|
|
1461
|
-
<div class="tl-footer__top">
|
|
1462
|
-
<div class="tl-footer__group">
|
|
1463
|
-
<button class="tl-footer__top-title">Resources</button>
|
|
1464
|
-
<a class="tl-footer__link" href="#">Documentation</a>
|
|
1465
|
-
<a class="tl-footer__link" href="#">API Reference</a>
|
|
1466
|
-
</div>
|
|
1467
|
-
<div class="tl-footer__group">
|
|
1468
|
-
<button class="tl-footer__top-title">Support</button>
|
|
1469
|
-
<a class="tl-footer__link" href="#">Contact</a>
|
|
1470
|
-
<a class="tl-footer__link" href="#">FAQ</a>
|
|
1471
|
-
</div>
|
|
1472
|
-
</div>
|
|
1473
|
-
|
|
1474
|
-
<!-- Main section with brand -->
|
|
1475
|
-
<div class="tl-footer__main">
|
|
1476
|
-
<div class="tl-footer__main-top">
|
|
1477
|
-
<div class="tl-footer__main-top--start">
|
|
1478
|
-
<div class="tl-footer__group">
|
|
1479
|
-
<a class="tl-footer__link" href="#">Privacy Policy</a>
|
|
1480
|
-
<a class="tl-footer__link" href="#">Cookie Policy</a>
|
|
1481
|
-
</div>
|
|
1482
|
-
</div>
|
|
1483
|
-
</div>
|
|
1484
|
-
<div class="tl-footer__main-bottom">
|
|
1485
|
-
<p class="tl-footer__copyright">© 2025 Scania CV AB</p>
|
|
1486
|
-
<span class="tl-footer__brand">Scania</span>
|
|
1487
|
-
</div>
|
|
1488
|
-
</div>
|
|
1489
|
-
</footer>
|
|
1490
|
-
```
|
|
1491
|
-
|
|
1492
|
-
---
|
|
1493
|
-
|
|
1494
|
-
## Side Menu
|
|
1495
|
-
|
|
1496
|
-
**Classes**: `tl-side-menu`
|
|
1497
|
-
**Modifiers**: `tl-side-menu--persistent`, `tl-side-menu--collapsed`
|
|
1498
|
-
|
|
1499
|
-
```html
|
|
1500
|
-
<nav class="tl-side-menu tl-side-menu--persistent" aria-label="Side navigation">
|
|
1501
|
-
<div class="tl-side-menu__wrapper tl-side-menu__wrapper--open">
|
|
1502
|
-
<div class="tl-side-menu__overlay"></div>
|
|
1503
|
-
<aside class="tl-side-menu__aside">
|
|
1504
|
-
<div class="tl-side-menu__navigation">
|
|
1505
|
-
<div class="tl-side-menu__list-wrapper">
|
|
1506
|
-
<ul class="tl-side-menu__upper-list">
|
|
1507
|
-
<li>
|
|
1508
|
-
<a
|
|
1509
|
-
class="tl-side-menu__item tl-side-menu__item--selected"
|
|
1510
|
-
href="/dashboard"
|
|
1511
|
-
>
|
|
1512
|
-
<span class="tl-icon tl-icon--dashboard"></span>
|
|
1513
|
-
Dashboard
|
|
1514
|
-
</a>
|
|
1515
|
-
</li>
|
|
1516
|
-
<li>
|
|
1517
|
-
<!-- Dropdown -->
|
|
1518
|
-
<div class="tl-side-menu__dropdown">
|
|
1519
|
-
<button class="tl-side-menu__item">
|
|
1520
|
-
<span class="tl-icon tl-icon--settings"></span>
|
|
1521
|
-
Settings
|
|
1522
|
-
</button>
|
|
1523
|
-
<div class="tl-side-menu__dropdown-menu">
|
|
1524
|
-
<ul class="tl-side-menu__dropdown-list">
|
|
1525
|
-
<li>
|
|
1526
|
-
<a
|
|
1527
|
-
class="tl-side-menu__dropdown-item"
|
|
1528
|
-
href="/settings/general"
|
|
1529
|
-
>General</a
|
|
1530
|
-
>
|
|
1531
|
-
</li>
|
|
1532
|
-
<li>
|
|
1533
|
-
<a
|
|
1534
|
-
class="tl-side-menu__dropdown-item"
|
|
1535
|
-
href="/settings/account"
|
|
1536
|
-
>Account</a
|
|
1537
|
-
>
|
|
1538
|
-
</li>
|
|
1539
|
-
</ul>
|
|
1540
|
-
</div>
|
|
1541
|
-
</div>
|
|
1542
|
-
</li>
|
|
1543
|
-
</ul>
|
|
1544
|
-
</div>
|
|
1545
|
-
</div>
|
|
1546
|
-
</aside>
|
|
1547
|
-
</div>
|
|
1548
|
-
</nav>
|
|
1549
|
-
```
|
|
1550
|
-
|
|
1551
|
-
---
|
|
1552
|
-
|
|
1553
|
-
## 05-guidelines
|
|
1554
|
-
|
|
1555
|
-
# Guidelines
|
|
1556
|
-
|
|
1557
|
-
## Spacing & Sizing Rules
|
|
1558
|
-
|
|
1559
|
-
### Spacing Custom Properties (available globally)
|
|
1560
|
-
|
|
1561
|
-
These are used by components internally and can be used for custom layouts:
|
|
1562
|
-
|
|
1563
|
-
- `--tds-spacing-element-4` (4px)
|
|
1564
|
-
- `--tds-spacing-element-8` (8px)
|
|
1565
|
-
- `--tds-spacing-element-12` (12px)
|
|
1566
|
-
- `--tds-spacing-element-16` (16px)
|
|
1567
|
-
- `--tds-spacing-element-20` (20px)
|
|
1568
|
-
- `--tds-spacing-element-24` (24px)
|
|
1569
|
-
- `--tds-spacing-element-32` (32px)
|
|
1570
|
-
- `--tds-spacing-element-48` (48px)
|
|
1571
|
-
- `--tds-spacing-layout-64` (64px)
|
|
1572
|
-
|
|
1573
|
-
### Rules
|
|
1574
|
-
|
|
1575
|
-
1. Use `var(--dimension-space-small)` (16px) as the base gap between elements.
|
|
1576
|
-
2. Use `var(--dimension-space-medium)` (24px) for section padding.
|
|
1577
|
-
3. Use `var(--dimension-space-large)` (48px) for major section separators.
|
|
1578
|
-
4. Component height follows the sizing convention: sm=40px, md=48px, lg=56px.
|
|
1579
|
-
|
|
1580
|
-
---
|
|
1581
|
-
|
|
1582
|
-
## Color Usage
|
|
1583
|
-
|
|
1584
|
-
### Semantic Color Usage
|
|
1585
|
-
|
|
1586
|
-
| Purpose | Token to Use |
|
|
1587
|
-
| ------------------------- | --------------------------------------------- |
|
|
1588
|
-
| Page background | `var(--color-background-base)` |
|
|
1589
|
-
| Card/section background | `var(--color-background-layer-01)` |
|
|
1590
|
-
| Nested section background | `var(--color-background-layer-02)` |
|
|
1591
|
-
| Primary heading text | `var(--color-foreground-text-strong)` |
|
|
1592
|
-
| Secondary text | `var(--color-foreground-text-defined)` |
|
|
1593
|
-
| Subtle/hint text | `var(--color-foreground-text-subtle)` |
|
|
1594
|
-
| Link text | `var(--color-foreground-text-accent-default)` |
|
|
1595
|
-
| Disabled text | `var(--color-foreground-text-disabled)` |
|
|
1596
|
-
| Default border | `var(--color-foreground-border-soft)` |
|
|
1597
|
-
| Focus outline | `var(--color-foreground-border-accent-focus)` |
|
|
1598
|
-
| Success state | `var(--color-system-success-default)` |
|
|
1599
|
-
| Warning state | `var(--color-system-warning-default)` |
|
|
1600
|
-
| Error/danger state | `var(--color-system-danger-default)` |
|
|
1601
|
-
| Info state | `var(--color-system-info-default)` |
|
|
1602
|
-
|
|
1603
|
-
### RULE: Never hardcode colors. Always use CSS custom properties.
|
|
1604
|
-
|
|
1605
|
-
---
|
|
1606
|
-
|
|
1607
|
-
## Responsiveness
|
|
1608
|
-
|
|
1609
|
-
### Breakpoints
|
|
1610
|
-
|
|
1611
|
-
| Name | Width | CSS |
|
|
1612
|
-
| ------- | -------- | ---------------------------- |
|
|
1613
|
-
| Mobile | < 672px | `@media (max-width: 671px)` |
|
|
1614
|
-
| Tablet | ≥ 672px | `@media (min-width: 672px)` |
|
|
1615
|
-
| Desktop | ≥ 992px | `@media (min-width: 992px)` |
|
|
1616
|
-
| Wide | ≥ 1056px | `@media (min-width: 1056px)` |
|
|
1617
|
-
| X-Wide | ≥ 1312px | `@media (min-width: 1312px)` |
|
|
1618
|
-
| XX-Wide | ≥ 1584px | `@media (min-width: 1584px)` |
|
|
1619
|
-
|
|
1620
|
-
### Rules
|
|
1621
|
-
|
|
1622
|
-
1. **Mobile-first**: Write base styles for mobile, add media queries for larger screens.
|
|
1623
|
-
2. Header nav items hide below 992px (burger menu shows).
|
|
1624
|
-
3. Side menu collapses to overlay below 992px.
|
|
1625
|
-
4. Footer top section stacks vertically below 992px.
|
|
1626
|
-
5. Modal widths are responsive (100% on mobile, percentage-based on desktop).
|
|
1627
|
-
|
|
1628
|
-
---
|
|
1629
|
-
|
|
1630
|
-
## Accessibility (a11y)
|
|
1631
|
-
|
|
1632
|
-
### Required ARIA Attributes
|
|
1633
|
-
|
|
1634
|
-
| Component | Required ARIA |
|
|
1635
|
-
| ------------- | ----------------------------------------------------------------------------- |
|
|
1636
|
-
| Button | `aria-label` for icon-only buttons |
|
|
1637
|
-
| Modal | `role="dialog"`, `aria-modal="true"`, `aria-labelledby` |
|
|
1638
|
-
| Accordion | `aria-expanded="true/false"` on trigger |
|
|
1639
|
-
| Tabs | `role="tablist"`, `role="tab"`, `aria-selected` |
|
|
1640
|
-
| Dropdown | `aria-expanded`, `aria-haspopup="listbox"`, `role="listbox"`, `role="option"` |
|
|
1641
|
-
| Breadcrumbs | `aria-label="Breadcrumb"`, `aria-current="page"` on last item |
|
|
1642
|
-
| Toast/Banner | `role="alert"` |
|
|
1643
|
-
| Tooltip | `role="tooltip"`, `aria-describedby` on trigger |
|
|
1644
|
-
| Spinner | `aria-label="Loading"`, `role="img"` |
|
|
1645
|
-
| Close buttons | `aria-label="Close"` or `aria-label="Dismiss"` |
|
|
1646
|
-
| Navigation | `aria-label` on `<nav>` elements |
|
|
1647
|
-
|
|
1648
|
-
### Focus Management
|
|
1649
|
-
|
|
1650
|
-
- All interactive elements have `:focus-visible` styles (2px solid blue-400 outline).
|
|
1651
|
-
- Focus outline uses `var(--color-foreground-border-accent-focus)`.
|
|
1652
|
-
- Modals should trap focus.
|
|
1653
|
-
- Side menu overlay closes on Escape.
|
|
1654
|
-
|
|
1655
|
-
### Contrast
|
|
1656
|
-
|
|
1657
|
-
- Use semantic tokens (they meet WCAG 2.1 AA contrast requirements).
|
|
1658
|
-
- Never override text colors with lighter alternatives.
|
|
1659
|
-
- `--color-foreground-text-strong` on `--color-background-base` = ≥4.5:1 ratio.
|
|
1660
|
-
|
|
1661
|
-
---
|
|
1662
|
-
|
|
1663
|
-
## Code Conventions
|
|
1664
|
-
|
|
1665
|
-
### BEM Naming Pattern
|
|
1666
|
-
|
|
1667
|
-
```
|
|
1668
|
-
.tl-{block} → Component root
|
|
1669
|
-
.tl-{block}__{element} → Sub-part of component
|
|
1670
|
-
.tl-{block}--{modifier} → Variant/state
|
|
1671
|
-
.tl-{block}__{element}--{mod} → Element variant
|
|
1672
|
-
```
|
|
1673
|
-
|
|
1674
|
-
### Class Order in HTML
|
|
1675
|
-
|
|
1676
|
-
1. Base class first: `tl-button`
|
|
1677
|
-
2. Variant modifier: `tl-button--primary`
|
|
1678
|
-
3. Size modifier: `tl-button--md`
|
|
1679
|
-
4. State modifier: `tl-button--full-width`
|
|
1680
|
-
|
|
1681
|
-
Example: `class="tl-button tl-button--primary tl-button--md tl-button--full-width"`
|
|
1682
|
-
|
|
1683
|
-
### Rules
|
|
1684
|
-
|
|
1685
|
-
1. **NEVER write custom CSS** if a Tegel Lite class already exists for the purpose.
|
|
1686
|
-
2. **NEVER use inline styles for colors, spacing, or any design properties.** ALWAYS use CSS classes with Tegel tokens.
|
|
1687
|
-
- ❌ BAD: `<span style="background-color: var(--color-system-success-discrete);">Active</span>`
|
|
1688
|
-
- ✅ GOOD: Create a CSS class `.status-badge--success { background-color: var(--color-system-success-discrete); }`
|
|
1689
|
-
3. **NEVER add inline styles to Tegel components.** If a component doesn't have the variant you need, create a custom component.
|
|
1690
|
-
4. **ALWAYS use semantic HTML** (`<button>`, `<a>`, `<nav>`, `<header>`, etc.).
|
|
1691
|
-
5. **ALWAYS wrap the app** in `<body class="scania tds-mode-light">`.
|
|
1692
|
-
6. When building custom components, use Tegel tokens for all colors, spacing, and typography.
|
|
1693
|
-
7. Keep custom CSS in separate files, never modify the Tegel Lite CSS files.
|
|
1694
|
-
|
|
1695
|
-
---
|
|
1696
|
-
|
|
1697
|
-
## 06-patterns
|
|
1698
|
-
|
|
1699
|
-
# Composed Page Patterns
|
|
1700
|
-
|
|
1701
|
-
## Login Page
|
|
1702
|
-
|
|
1703
|
-
```html
|
|
1704
|
-
<body class="scania tds-mode-light">
|
|
1705
|
-
<div
|
|
1706
|
-
style="display: flex; align-items: center; justify-content: center; min-height: 100vh; background-color: var(--color-background-base);"
|
|
1707
|
-
>
|
|
1708
|
-
<div class="tl-card" style="width: 400px; max-width: 100%;">
|
|
1709
|
-
<div class="tl-card__header">
|
|
1710
|
-
<div class="tl-card__headings">
|
|
1711
|
-
<span class="tl-card__title">Sign In</span>
|
|
1712
|
-
<span class="tl-card__subtitle">Enter your credentials</span>
|
|
1713
|
-
</div>
|
|
1714
|
-
</div>
|
|
1715
|
-
<div class="tl-card__body">
|
|
1716
|
-
<div class="tl-card__content" style="max-inline-size: unset;">
|
|
1717
|
-
<!-- Email field -->
|
|
1718
|
-
<div
|
|
1719
|
-
class="tl-text-field tl-text-field--lg"
|
|
1720
|
-
style="margin-bottom: 16px;"
|
|
1721
|
-
>
|
|
1722
|
-
<label class="tl-text-field__label" for="login-email">Email</label>
|
|
1723
|
-
<input
|
|
1724
|
-
class="tl-text-field__input"
|
|
1725
|
-
id="login-email"
|
|
1726
|
-
type="email"
|
|
1727
|
-
placeholder="user@scania.com"
|
|
1728
|
-
/>
|
|
1729
|
-
</div>
|
|
1730
|
-
<!-- Password field -->
|
|
1731
|
-
<div
|
|
1732
|
-
class="tl-text-field tl-text-field--lg"
|
|
1733
|
-
style="margin-bottom: 24px;"
|
|
1734
|
-
>
|
|
1735
|
-
<label class="tl-text-field__label" for="login-pass"
|
|
1736
|
-
>Password</label
|
|
1737
|
-
>
|
|
1738
|
-
<input
|
|
1739
|
-
class="tl-text-field__input"
|
|
1740
|
-
id="login-pass"
|
|
1741
|
-
type="password"
|
|
1742
|
-
placeholder="Enter password"
|
|
1743
|
-
/>
|
|
1744
|
-
</div>
|
|
1745
|
-
<button
|
|
1746
|
-
class="tl-button tl-button--primary tl-button--md tl-button--full-width"
|
|
1747
|
-
>
|
|
1748
|
-
Sign In
|
|
1749
|
-
</button>
|
|
1750
|
-
</div>
|
|
1751
|
-
</div>
|
|
1752
|
-
</div>
|
|
1753
|
-
</div>
|
|
1754
|
-
</body>
|
|
1755
|
-
```
|
|
1756
|
-
|
|
1757
|
-
---
|
|
1758
|
-
|
|
1759
|
-
## Dashboard Layout (Header + Sidebar + Content)
|
|
1760
|
-
|
|
1761
|
-
```html
|
|
1762
|
-
<body class="scania tds-mode-light">
|
|
1763
|
-
<!-- Header -->
|
|
1764
|
-
<header class="tl-header">
|
|
1765
|
-
<nav class="tl-header__nav">
|
|
1766
|
-
<ul class="tl-header__list">
|
|
1767
|
-
<li class="tl-header__item">
|
|
1768
|
-
<a class="tl-header__item-wrapper" href="/"
|
|
1769
|
-
><span class="tl-header__brand"></span
|
|
1770
|
-
></a>
|
|
1771
|
-
</li>
|
|
1772
|
-
<li class="tl-header__item">
|
|
1773
|
-
<div class="tl-header__title">
|
|
1774
|
-
<span class="tl-header__title-text">Fleet Manager</span>
|
|
1775
|
-
</div>
|
|
1776
|
-
</li>
|
|
1777
|
-
<li class="tl-header__middle-spacer"></li>
|
|
1778
|
-
<li class="tl-header__item">
|
|
1779
|
-
<button class="tl-header__item-wrapper" aria-label="Notifications">
|
|
1780
|
-
<span class="tl-icon tl-icon--notification"></span>
|
|
1781
|
-
</button>
|
|
1782
|
-
</li>
|
|
1783
|
-
</ul>
|
|
1784
|
-
</nav>
|
|
1785
|
-
</header>
|
|
1786
|
-
|
|
1787
|
-
<!-- Layout -->
|
|
1788
|
-
<div style="display: flex; min-height: calc(100vh - 64px);">
|
|
1789
|
-
<!-- Side Menu -->
|
|
1790
|
-
<nav
|
|
1791
|
-
class="tl-side-menu tl-side-menu--persistent"
|
|
1792
|
-
aria-label="Main navigation"
|
|
1793
|
-
style="position: static; height: auto;"
|
|
1794
|
-
>
|
|
1795
|
-
<div class="tl-side-menu__wrapper tl-side-menu__wrapper--open">
|
|
1796
|
-
<aside class="tl-side-menu__aside">
|
|
1797
|
-
<div class="tl-side-menu__navigation">
|
|
1798
|
-
<div class="tl-side-menu__list-wrapper">
|
|
1799
|
-
<ul class="tl-side-menu__upper-list">
|
|
1800
|
-
<li>
|
|
1801
|
-
<a
|
|
1802
|
-
class="tl-side-menu__item tl-side-menu__item--selected"
|
|
1803
|
-
href="/dashboard"
|
|
1804
|
-
>
|
|
1805
|
-
<span class="tl-icon tl-icon--dashboard"></span> Dashboard
|
|
1806
|
-
</a>
|
|
1807
|
-
</li>
|
|
1808
|
-
<li>
|
|
1809
|
-
<a class="tl-side-menu__item" href="/vehicles">
|
|
1810
|
-
<span class="tl-icon tl-icon--truck"></span> Vehicles
|
|
1811
|
-
</a>
|
|
1812
|
-
</li>
|
|
1813
|
-
</ul>
|
|
1814
|
-
</div>
|
|
1815
|
-
</div>
|
|
1816
|
-
</aside>
|
|
1817
|
-
</div>
|
|
1818
|
-
</nav>
|
|
1819
|
-
|
|
1820
|
-
<!-- Main Content -->
|
|
1821
|
-
<main
|
|
1822
|
-
style="flex: 1; padding: var(--dimension-space-medium); background-color: var(--color-background-base);"
|
|
1823
|
-
>
|
|
1824
|
-
<!-- Cards grid -->
|
|
1825
|
-
<div
|
|
1826
|
-
style="display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; margin-bottom: 24px;"
|
|
1827
|
-
>
|
|
1828
|
-
<div class="tl-card">
|
|
1829
|
-
<div class="tl-card__header">
|
|
1830
|
-
<div class="tl-card__headings">
|
|
1831
|
-
<span class="tl-card__title">Total Vehicles</span>
|
|
1832
|
-
</div>
|
|
1833
|
-
</div>
|
|
1834
|
-
<div class="tl-card__body">
|
|
1835
|
-
<div
|
|
1836
|
-
class="tl-card__content"
|
|
1837
|
-
style="max-inline-size: unset; font-size: 32px; font-weight: 700;"
|
|
1838
|
-
>
|
|
1839
|
-
142
|
|
1840
|
-
</div>
|
|
1841
|
-
</div>
|
|
1842
|
-
</div>
|
|
1843
|
-
</div>
|
|
1844
|
-
|
|
1845
|
-
<!-- Table -->
|
|
1846
|
-
<table class="tl-table tl-table--responsive">
|
|
1847
|
-
<thead class="tl-table__header">
|
|
1848
|
-
<tr class="tl-table__row">
|
|
1849
|
-
<th class="tl-table__header-cell">Vehicle</th>
|
|
1850
|
-
<th class="tl-table__header-cell">Status</th>
|
|
1851
|
-
<th class="tl-table__header-cell">Location</th>
|
|
1852
|
-
</tr>
|
|
1853
|
-
</thead>
|
|
1854
|
-
<tbody class="tl-table__body">
|
|
1855
|
-
<tr class="tl-table__row">
|
|
1856
|
-
<td class="tl-table__body-cell">SCN-2024-001</td>
|
|
1857
|
-
<td class="tl-table__body-cell">Active</td>
|
|
1858
|
-
<td class="tl-table__body-cell">Södertälje</td>
|
|
1859
|
-
</tr>
|
|
1860
|
-
</tbody>
|
|
1861
|
-
</table>
|
|
1862
|
-
</main>
|
|
1863
|
-
</div>
|
|
1864
|
-
</body>
|
|
1865
|
-
```
|
|
1866
|
-
|
|
1867
|
-
---
|
|
1868
|
-
|
|
1869
|
-
## Form Page
|
|
1870
|
-
|
|
1871
|
-
```html
|
|
1872
|
-
<main
|
|
1873
|
-
style="max-width: 600px; margin: 0 auto; padding: var(--dimension-space-medium);"
|
|
1874
|
-
>
|
|
1875
|
-
<h2
|
|
1876
|
-
style="font-family: var(--scania-font-family-default); font-weight: var(--scania-font-weight-bold); margin-bottom: 24px;"
|
|
1877
|
-
>
|
|
1878
|
-
New Vehicle Registration
|
|
1879
|
-
</h2>
|
|
1880
|
-
|
|
1881
|
-
<form>
|
|
1882
|
-
<div style="display: flex; flex-direction: column; gap: 16px;">
|
|
1883
|
-
<div class="tl-text-field tl-text-field--lg">
|
|
1884
|
-
<label class="tl-text-field__label" for="vin">VIN Number</label>
|
|
1885
|
-
<input
|
|
1886
|
-
class="tl-text-field__input"
|
|
1887
|
-
id="vin"
|
|
1888
|
-
type="text"
|
|
1889
|
-
placeholder="Enter VIN"
|
|
1890
|
-
/>
|
|
1891
|
-
</div>
|
|
1892
|
-
|
|
1893
|
-
<div class="tl-dropdown tl-dropdown--lg">
|
|
1894
|
-
<label class="tl-dropdown__label" for="type">Vehicle Type</label>
|
|
1895
|
-
<select class="tl-dropdown__select" id="type">
|
|
1896
|
-
<option value="">Select type</option>
|
|
1897
|
-
<option value="truck">Truck</option>
|
|
1898
|
-
<option value="bus">Bus</option>
|
|
1899
|
-
</select>
|
|
1900
|
-
</div>
|
|
1901
|
-
|
|
1902
|
-
<div class="tl-datetime">
|
|
1903
|
-
<label class="tl-datetime__label" for="reg-date"
|
|
1904
|
-
>Registration Date</label
|
|
1905
|
-
>
|
|
1906
|
-
<div class="tl-datetime__wrapper">
|
|
1907
|
-
<input class="tl-datetime__input" id="reg-date" type="date" />
|
|
1908
|
-
</div>
|
|
1909
|
-
</div>
|
|
1910
|
-
|
|
1911
|
-
<div class="tl-textarea">
|
|
1912
|
-
<label class="tl-textarea__label" for="notes">Notes</label>
|
|
1913
|
-
<textarea
|
|
1914
|
-
class="tl-textarea__input"
|
|
1915
|
-
id="notes"
|
|
1916
|
-
rows="4"
|
|
1917
|
-
placeholder="Additional details..."
|
|
1918
|
-
></textarea>
|
|
1919
|
-
</div>
|
|
1920
|
-
|
|
1921
|
-
<label class="tl-checkbox">
|
|
1922
|
-
<input class="tl-checkbox__input" type="checkbox" />
|
|
1923
|
-
<span class="tl-checkbox__label"
|
|
1924
|
-
>I confirm all information is correct</span
|
|
1925
|
-
>
|
|
1926
|
-
</label>
|
|
1927
|
-
|
|
1928
|
-
<div style="display: flex; gap: 16px; padding-top: 8px;">
|
|
1929
|
-
<button
|
|
1930
|
-
type="button"
|
|
1931
|
-
class="tl-button tl-button--secondary tl-button--md"
|
|
1932
|
-
>
|
|
1933
|
-
Cancel
|
|
1934
|
-
</button>
|
|
1935
|
-
<button
|
|
1936
|
-
type="submit"
|
|
1937
|
-
class="tl-button tl-button--primary tl-button--md"
|
|
1938
|
-
>
|
|
1939
|
-
Register
|
|
1940
|
-
</button>
|
|
1941
|
-
</div>
|
|
1942
|
-
</div>
|
|
1943
|
-
</form>
|
|
1944
|
-
</main>
|
|
1945
|
-
```
|
|
1946
|
-
|
|
1947
|
-
---
|
|
1948
|
-
|
|
1949
|
-
# AI Assistant Prompt Rules
|
|
1950
|
-
|
|
1951
|
-
## CRITICAL: NO INLINE STYLES
|
|
1952
|
-
|
|
1953
|
-
**NEVER EVER use inline `style=""` attributes for design properties on ANY element, especially not on Tegel components.**
|
|
1954
|
-
|
|
1955
|
-
This includes:
|
|
1956
|
-
|
|
1957
|
-
- ❌ Colors: `style="color: ..."` or `style="background-color: ..."`
|
|
1958
|
-
- ❌ Spacing: `style="padding: ..."` or `style="margin: ..."`
|
|
1959
|
-
- ❌ Typography: `style="font-size: ..."` or `style="font-weight: ..."`
|
|
1960
|
-
- ❌ Any design tokens: `style="background-color: var(--color-system-success-discrete);"`
|
|
1961
|
-
|
|
1962
|
-
**ALWAYS create CSS classes instead:**
|
|
1963
|
-
|
|
1964
|
-
- ✅ Define class in `<style>` section with Tegel tokens
|
|
1965
|
-
- ✅ Use BEM naming: `.custom-component--variant`
|
|
1966
|
-
- ✅ Mark with comment: `<!-- CUSTOM: Description -->`
|
|
1967
|
-
|
|
1968
|
-
**If a Tegel component doesn't have the variant you need (e.g., status badges), create a custom component with proper CSS classes, NOT inline styles.**
|
|
1969
|
-
|
|
1970
|
-
---
|
|
1971
|
-
|
|
1972
|
-
## Component Generation
|
|
1973
|
-
|
|
1974
|
-
1. When the user asks for a button, ALWAYS default to `tl-button tl-button--md` (variant is optional).
|
|
1975
|
-
2. When the user asks for a button with icon:
|
|
1976
|
-
- ALWAYS add `tl-button--icon` modifier
|
|
1977
|
-
- ALWAYS put text BEFORE the icon
|
|
1978
|
-
- ALWAYS add `aria-hidden="true"` to the icon
|
|
1979
|
-
- Example: `<button class="tl-button tl-button--icon tl-button--md">Save<span class="tl-icon tl-icon--save" aria-hidden="true"></span></button>`
|
|
1980
|
-
3. When the user asks for an icon-only button:
|
|
1981
|
-
- ALWAYS add `tl-button--only-icon` modifier
|
|
1982
|
-
- ALWAYS add `aria-label` attribute describing the action
|
|
1983
|
-
- Example: `<button class="tl-button tl-button--only-icon tl-button--md" aria-label="Settings"><span class="tl-icon tl-icon--settings"></span></button>`
|
|
1984
|
-
4. When the user asks for an input/text field, ALWAYS default to `tl-text-field tl-text-field--lg` with an external label.
|
|
1985
|
-
5. When the user asks for a card, ALWAYS include `tl-card__header` and `tl-card__body` sections.
|
|
1986
|
-
6. When the user asks for a table, ALWAYS include `tl-table__header` with `th.tl-table__header-cell` and `tl-table__body`.
|
|
1987
|
-
|
|
1988
|
-
## Code Quality
|
|
1989
|
-
|
|
1990
|
-
7. Generate ALWAYS complete, production-ready HTML – never pseudocode.
|
|
1991
|
-
8. Generate ALWAYS all necessary wrapper elements (e.g., `tl-card__body` > `tl-card__content`).
|
|
1992
|
-
9. Include ALWAYS relevant ARIA attributes for accessibility:
|
|
1993
|
-
- Decorative icons in buttons with text: `aria-hidden="true"`
|
|
1994
|
-
- Icon-only buttons: `aria-label="Action description"`
|
|
1995
|
-
- Form labels: proper `for` and `id` attributes
|
|
1996
|
-
10. Comment HTML with `<!-- -->` to explain structure sections.
|
|
1997
|
-
11. Use ALWAYS the `scania tds-mode-light` classes on the `<body>` or root element.
|
|
1998
|
-
|
|
1999
|
-
## Token Usage
|
|
2000
|
-
|
|
2001
|
-
12. Use NEVER hardcoded color values – ALWAYS CSS custom properties.
|
|
2002
|
-
13. Use NEVER hardcoded pixel spacing – prefer Tegel spacing tokens.
|
|
2003
|
-
14. Use NEVER inline styles for any design properties (color, background, spacing, typography).
|
|
2004
|
-
- ❌ `style="color: blue"` or `style="color: var(--color-foreground-text-accent-default)"`
|
|
2005
|
-
- ✅ Create CSS class: `.custom-text { color: var(--color-foreground-text-accent-default); }`
|
|
2006
|
-
15. Use NEVER `style="background: #f5f5f5"` – create a CSS class instead.
|
|
2007
|
-
16. If a Tegel component lacks a needed variant, create a CUSTOM component with BEM classes, not inline styles.
|
|
2008
|
-
|
|
2009
|
-
## Custom Components
|
|
2010
|
-
|
|
2011
|
-
17. If the user requests a component that doesn't exist in Tegel Lite, build it using existing tokens and classes, and clearly mark it with a comment: `<!-- CUSTOM: Not a native Tegel Lite component -->`.
|
|
2012
|
-
18. Custom components should follow the BEM naming convention: `.tl-custom-{name}__element--modifier`.
|
|
2013
|
-
|
|
2014
|
-
## File Structure
|
|
2015
|
-
|
|
2016
|
-
19. Always import CSS files in the correct order: variables → global → components.
|
|
2017
|
-
20. Never modify the Tegel Lite source CSS files.
|
|
2018
|
-
21. Place custom overrides in a separate stylesheet loaded AFTER the Tegel files.
|
|
2019
|
-
|
|
2020
|
-
## Dark Mode
|
|
2021
|
-
|
|
2022
|
-
22. To switch to dark mode, replace `tds-mode-light` with `tds-mode-dark` on the wrapper element.
|
|
2023
|
-
23. All components automatically adapt – no additional work needed.
|
|
2024
|
-
24. When showing dark mode examples, add `tds-mode-dark` to the root wrapper.
|
|
2025
|
-
|
|
2026
|
-
## Icon Usage
|
|
2027
|
-
|
|
2028
|
-
25. Icons use the pattern `tl-icon tl-icon--{name}` and optionally `tl-icon--{size}`.
|
|
2029
|
-
26. Icons inherit color from parent. Use `color: var(--color-foreground-icon-strong)` on parent if needed.
|
|
2030
|
-
27. Decorative icons in buttons with text MUST have `aria-hidden="true"`.
|
|
2031
|
-
28. Icon-only interactive elements MUST have `aria-label` describing the action.
|
|
2032
|
-
|
|
2033
|
-
## Size Convention
|
|
2034
|
-
|
|
2035
|
-
29. Component sizes follow this convention (unless stated otherwise):
|
|
2036
|
-
- `--xs` = 24px height (buttons only)
|
|
2037
|
-
- `--sm` = 40px height
|
|
2038
|
-
- `--md` = 48px height
|
|
2039
|
-
- `--lg` = 56px height (default for inputs)
|
|
2040
|
-
|
|
2041
|
-
## Mode Variants
|
|
2042
|
-
|
|
2043
|
-
30. Components with `--primary` use `var(--color-background-layer-01)`.
|
|
2044
|
-
31. Components with `--secondary` use `var(--color-background-layer-02)`.
|
|
2045
|
-
32. Variant modifiers (primary, secondary, ghost, danger) are optional for buttons – use based on context.
|