Skip to content

Commit f8b3fed

Browse files
refactor(style): DLT-3014 wrap all styles in css cascade layers (#1061)
1 parent 1cb91ea commit f8b3fed

100 files changed

Lines changed: 1200 additions & 194 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/dialtone-documentation/docs/.vuepress/baseComponents/DialtoneUsage.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div class="dialtone-usage">
3-
<div class="dialtone-usage__item dialtone-usage__item--do">
3+
<div v-if="$slots.do" class="dialtone-usage__item dialtone-usage__item--do">
44
<h3 class="dialtone-usage__hd dialtone-usage__hd--do">
55
<dt-icon name="check" size="200" />
66
<div class="dialtone-usage__label">
@@ -11,7 +11,7 @@
1111
<slot name="do" />
1212
</div>
1313
</div>
14-
<div class="dialtone-usage__item dialtone-usage__item--dont">
14+
<div v-if="$slots.dont" class="dialtone-usage__item dialtone-usage__item--dont">
1515
<h3 class="dialtone-usage__hd dialtone-usage__hd--dont">
1616
<dt-icon name="close" size="200" />
1717
<div class="dialtone-usage__label">

apps/dialtone-documentation/docs/_data/site-nav.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,10 @@
174174
"text": "Theme and Mode",
175175
"link": "/guides/theme-and-mode/"
176176
},
177+
{
178+
"text": "CSS Cascade Layers",
179+
"link": "/guides/css-layers/"
180+
},
177181
{
178182
"text": "Contributing",
179183
"link": "/guides/contributing/"

apps/dialtone-documentation/docs/components/text.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Declare the role of the content. Default will inherit styles from the parent.
6262

6363
<code-well-header>
6464
<dt-stack gap="400" :direction="{ 'default': 'column', 'md': 'row' }" align="baseline">
65-
<dt-text kind="headline">Headline</dt-text>
65+
<dt-text kind="headline" as="span">Headline</dt-text>
6666
<dt-text kind="body">Body</dt-text>
6767
<dt-text kind="label">Label</dt-text>
6868
<dt-text kind="code">Code</dt-text>
@@ -152,9 +152,9 @@ All kinds support `size` prop, but not all sizes are available for each kind. Wh
152152
<td class="d-ta-center">
153153
<dt-text kind="body" as="p" size="lg">Text</dt-text>
154154
</td>
155-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
156-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
157-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
155+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
156+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
157+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
158158
</tr>
159159
<tr class="d-va-baseline">
160160
<th scope="row">
@@ -172,9 +172,9 @@ All kinds support `size` prop, but not all sizes are available for each kind. Wh
172172
<td class="d-ta-center">
173173
<dt-text kind="label" as="p" size="lg">Text</dt-text>
174174
</td>
175-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
176-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
177-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
175+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
176+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
177+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
178178
</tr>
179179
<tr class="d-va-baseline">
180180
<th scope="row">
@@ -192,9 +192,9 @@ All kinds support `size` prop, but not all sizes are available for each kind. Wh
192192
<td class="d-ta-center">
193193
<dt-text kind="code" as="code" size="lg" class="d-bgc-transparent" tone="secondary">Text</dt-text>
194194
</td>
195-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
196-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
197-
<td class="d-ta-center"><dt-text tone="muted" size="sm" title="not available">-</dt-text></td>
195+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
196+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
197+
<td class="d-ta-center"><dt-text tone="muted" kind="body" size="sm" title="not available">-</dt-text></td>
198198
</tr>
199199
</table>
200200
</dt-stack>
@@ -400,9 +400,9 @@ vueCode='
400400

401401
<code-well-header>
402402
<dt-stack class="d-w100p" align="start" gap="500" :direction="{ 'default': 'column', 'md': 'row' }">
403-
<dt-text as="p" maxLines="2">Welcome to Dialpad, the most modern, AI-powered business communications platform. We’ve taken every form of communication that you rely on and unified it into one app. Calling a client? Meeting with your team? Texting a colleague? It’s all here, on all your devices. AI is by your side to transform your conversations into something you can see and use, giving you and your team a deeper look into action items and insights. Dialpad AI does the legwork to capture the details that matter most while you make and receive calls, send messages, and join meetings in an instant.</dt-text>
404-
<dt-text as="p" maxLines="4">Welcome to Dialpad, the most modern, AI-powered business communications platform. We’ve taken every form of communication that you rely on and unified it into one app. Calling a client? Meeting with your team? Texting a colleague? It’s all here, on all your devices. AI is by your side to transform your conversations into something you can see and use, giving you and your team a deeper look into action items and insights. Dialpad AI does the legwork to capture the details that matter most while you make and receive calls, send messages, and join meetings in an instant.</dt-text>
405-
<dt-text as="p" maxLines="6">Welcome to Dialpad, the most modern, AI-powered business communications platform. We’ve taken every form of communication that you rely on and unified it into one app. Calling a client? Meeting with your team? Texting a colleague? It’s all here, on all your devices. AI is by your side to transform your conversations into something you can see and use, giving you and your team a deeper look into action items and insights. Dialpad AI does the legwork to capture the details that matter most while you make and receive calls, send messages, and join meetings in an instant.</dt-text>
403+
<dt-text as="p" :maxLines="2">Welcome to Dialpad, the most modern, AI-powered business communications platform. We’ve taken every form of communication that you rely on and unified it into one app. Calling a client? Meeting with your team? Texting a colleague? It’s all here, on all your devices. AI is by your side to transform your conversations into something you can see and use, giving you and your team a deeper look into action items and insights. Dialpad AI does the legwork to capture the details that matter most while you make and receive calls, send messages, and join meetings in an instant.</dt-text>
404+
<dt-text as="p" :maxLines="4">Welcome to Dialpad, the most modern, AI-powered business communications platform. We’ve taken every form of communication that you rely on and unified it into one app. Calling a client? Meeting with your team? Texting a colleague? It’s all here, on all your devices. AI is by your side to transform your conversations into something you can see and use, giving you and your team a deeper look into action items and insights. Dialpad AI does the legwork to capture the details that matter most while you make and receive calls, send messages, and join meetings in an instant.</dt-text>
405+
<dt-text as="p" :maxLines="6">Welcome to Dialpad, the most modern, AI-powered business communications platform. We’ve taken every form of communication that you rely on and unified it into one app. Calling a client? Meeting with your team? Texting a colleague? It’s all here, on all your devices. AI is by your side to transform your conversations into something you can see and use, giving you and your team a deeper look into action items and insights. Dialpad AI does the legwork to capture the details that matter most while you make and receive calls, send messages, and join meetings in an instant.</dt-text>
406406
</dt-stack>
407407
</code-well-header>
408408

@@ -414,7 +414,7 @@ vueCode='
414414
<code-well-header>
415415
<dt-stack gap="400">
416416
<dt-stack direction="row" gap="400" class="d-jc-space-between d-ai-center">
417-
<dt-text kind="headline" size="lg">Demo</dt-text>
417+
<dt-text kind="headline" size="lg" as="h3">Demo</dt-text>
418418
<dt-stack direction="row" gap="400" align="center">
419419
<dt-text v-if="state.isApplied" as="code" kind="code" size="xs">
420420
max-lines="<strong>{{ state.value }}</strong>"
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
heading: Dialtone now uses CSS Cascade Layers
3+
author: Francis Rupert
4+
posted: '2026-2-23'
5+
excerpt: 'Dialtone now uses CSS Cascade Layers to organize all styles into a predictable hierarchy, improving specificity control and making overrides more predictable.'
6+
---
7+
8+
<BlogPost :author="$frontmatter.author" :posted="parse($frontmatter.posted, 'y-M-d', new Date())" :heading="$frontmatter.heading" :excerpt="$frontmatter.excerpt">
9+
10+
## TLDR
11+
12+
Dialtone now uses CSS Cascade Layers (`@layer`) to organize all styles into a predictable hierarchy. This improves specificity control, makes overrides more predictable, and eliminates the need for complex selector specificity hacks.
13+
14+
**For Consumers**: No breaking changes. Styles work exactly as before, just more reliably.
15+
16+
**For Contributors**: All new styles must be wrapped in the appropriate `@layer` block. See the [CSS Cascade Layers Guide](../../../guides/css-layers/) for details.
17+
18+
## What Changed
19+
20+
All Dialtone CSS is now organized into four cascade layers:
21+
22+
```css
23+
@layer dialtone.reset, dialtone.base, dialtone.components, dialtone.utilities;
24+
```
25+
26+
### Layer Hierarchy
27+
28+
1. **`dialtone.reset`** - CSS resets (normalize.css, typography resets)
29+
2. **`dialtone.base`** - Design tokens, fonts, themes, global styles
30+
3. **`dialtone.components`** - Component styles (buttons, inputs, modals, etc.)
31+
4. **`dialtone.utilities`** - Utility classes (spacing, colors, layout)
32+
33+
## Why This Matters
34+
35+
### Before: Specificity Wars
36+
37+
Previously, ensuring utilities could override components required:
38+
39+
- Adding `!important` to every utility
40+
- Carefully managing selector specificity
41+
- Loading CSS files in the correct order
42+
- Hoping third-party CSS didn't break things
43+
44+
### After: Predictable Cascade
45+
46+
With cascade layers:
47+
48+
-**Utilities always override components** - Layer order guarantees it
49+
-**No specificity hacks needed** - Layer priority beats specificity
50+
-**Clear organization** - Every style has a clear home
51+
-**Third-party CSS control** - Can layer external CSS between Dialtone layers
52+
53+
## How Layers Work
54+
55+
### Normal Cascade (Highest to Lowest Priority)
56+
57+
1. **Unlayered styles** (highest)
58+
2. `dialtone.utilities`
59+
3. `dialtone.components`
60+
4. `dialtone.base`
61+
5. `dialtone.reset` (lowest)
62+
63+
### With `!important` (Order Reverses!)
64+
65+
1. **`dialtone.reset !important`** (highest)
66+
2. `dialtone.base !important`
67+
3. `dialtone.components !important`
68+
4. `dialtone.utilities !important`
69+
5. **Unlayered `!important`** (lowest)
70+
71+
> **Why utilities use `!important`**: Dialtone utilities are in the last layer with `!important`, giving them the highest effective priority for overriding component styles while staying organized.
72+
73+
## For Consumers
74+
75+
### No Breaking Changes
76+
77+
Your existing code continues to work. Utility classes override components just as before, but now with guaranteed layer ordering.
78+
79+
### Writing Overrides
80+
81+
If you need to override Dialtone styles, create your own layer after utilities:
82+
83+
```css
84+
@layer dialtone.reset, dialtone.base, dialtone.components, dialtone.utilities, app;
85+
86+
@layer app {
87+
.my-custom-styles {
88+
/* Your overrides here */
89+
}
90+
}
91+
```
92+
93+
See [Using CSS Layers with Dialtone](../../../guides/css-layers/) for detailed guidance.
94+
95+
### Third-Party CSS
96+
97+
If you're using third-party CSS that conflicts with Dialtone, wrap it in a layer:
98+
99+
```css
100+
@layer dialtone.reset, dialtone.base, dialtone.components, third-party, dialtone.utilities;
101+
102+
@layer third-party {
103+
@import 'some-library/styles.css';
104+
}
105+
```
106+
107+
This ensures Dialtone utilities can still override third-party styles.
108+
109+
## For Contributors
110+
111+
### All Styles Must Be Layered
112+
113+
When adding new styles, wrap them in the appropriate layer:
114+
115+
**Components:**
116+
117+
```less
118+
@layer dialtone.components {
119+
.d-my-component {
120+
/* styles */
121+
}
122+
}
123+
```
124+
125+
**Utilities:**
126+
127+
```less
128+
@layer dialtone.utilities {
129+
.d-my-util { property: value !important; }
130+
}
131+
```
132+
133+
### Cross-Layer Mixins
134+
135+
To share styles between layers, extract parametric mixins **outside** `@layer` blocks:
136+
137+
```less
138+
// Outside @layer for cross-file access
139+
._my-mixin() {
140+
display: flex;
141+
align-items: center;
142+
}
143+
144+
@layer dialtone.components {
145+
.d-component { ._my-mixin(); }
146+
}
147+
```
148+
149+
### Validation
150+
151+
The build pipeline now validates that all Dialtone classes are properly layered. Unlayered classes will fail CI.
152+
153+
See the [CSS Layers Contributor Guide](../../../guides/css-layers/) for complete documentation.
154+
155+
## Examples
156+
157+
### Utility Classes Override Components
158+
159+
```html
160+
<!-- Component default: blue background -->
161+
<button class="d-btn d-bgc-critical">
162+
<!-- Utility wins: red background -->
163+
</button>
164+
```
165+
166+
### Responsive Utilities
167+
168+
Responsive utilities are now in the same layer as base utilities, ensuring consistent behavior:
169+
170+
```html
171+
<div class="d-d-none lg:d-d-block">
172+
<!-- Hidden by default, visible on large screens -->
173+
</div>
174+
```
175+
176+
### App Overrides
177+
178+
```css
179+
@layer app.overrides {
180+
.d-btn--custom {
181+
border-radius: 999px;
182+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
183+
}
184+
}
185+
```
186+
187+
## Browser Support
188+
189+
CSS Cascade Layers are supported in all modern browsers:
190+
191+
- Chrome 99+
192+
- Firefox 97+
193+
- Safari 15.4+
194+
- Edge 99+
195+
196+
For older browsers, styles still apply (unlayered), maintaining visual consistency with potentially different cascade behavior.
197+
198+
## Learn More
199+
200+
- [CSS Cascade Layers in Dialtone](../../../guides/css-layers/)
201+
- [MDN: CSS Cascade Layers](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@layer)
202+
- [CSS Cascade Layers Explainer](https://css.oddbird.net/layers/explainer/)
203+
204+
## Migration Path
205+
206+
No migration required for consumers. Existing Dialtone usage continues to work identically.
207+
208+
If you have custom CSS that conflicts with Dialtone, consider wrapping it in a layer as described in [Using CSS Layers with Dialtone](../../../guides/css-layers/).
209+
210+
</BlogPost>
211+
212+
<script setup>
213+
import BlogPost from '@baseComponents/BlogPost.vue';
214+
import { parse } from 'date-fns';
215+
</script>

apps/dialtone-documentation/docs/guides/contributing/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ To make code changes in our Design System please first read the
1616
[CONTRIBUTING.md](https://github.com/dialpad/dialtone/blob/staging/.github/CONTRIBUTING.md#contributing)
1717
in our Dialtone repository.
1818

19+
### CSS Architecture
20+
21+
Dialtone uses [CSS Cascade Layers](../css-layers/) to organize styles into a predictable hierarchy. When contributing CSS, all styles must be wrapped in the appropriate `@layer` block. Read the [CSS Layers Guide](../css-layers/) to understand where to place your styles.
22+
1923
## Adding Icons and Illustrations
2024

2125
If you need to add an icon into Dialtone, here’s how you would go about doing that.

0 commit comments

Comments
 (0)