mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-09 00:42:46 +08:00
334 lines
13 KiB
Markdown
334 lines
13 KiB
Markdown
|
|
# Non-Color Styling Hooks Guide
|
|||
|
|
|
|||
|
|
Reference for replacing hardcoded spacing, sizing, typography, border, radius, and shadow values with SLDS 2 styling hooks. These hooks use numbered scales with straightforward mappings — unlike color hooks, they rarely require context-based decisions.
|
|||
|
|
|
|||
|
|
**Pattern for all replacements:**
|
|||
|
|
```css
|
|||
|
|
property: var(--slds-g-[hook], originalValue);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Important: Only replace values that match a hook's actual rendered value.** If a hardcoded value falls between two hooks (e.g., `3px` when hooks offer `4px` and `8px`), leave it unchanged. The linter auto-fix handles exact matches; manual fixes should only apply when there's a clear correspondence. Forcing a non-matching value into the nearest hook changes the component's visual appearance.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Critical Rule: Never Invent Hooks
|
|||
|
|
|
|||
|
|
**Only use hooks that actually exist in SLDS 2.** The linter is the source of truth for which hooks exist and what values they map to. Do not:
|
|||
|
|
|
|||
|
|
- **Guess hook names** — Hooks like `--slds-g-spacing-medium`, `--slds-g-font-weight-bold`, `--slds-g-radius-large` do NOT exist. SLDS 2 uses numbered scales only (e.g., `--slds-g-spacing-4`, `--slds-g-font-weight-7`).
|
|||
|
|
- **Extrapolate patterns** — If you see `--slds-g-spacing-1` through `--slds-g-spacing-12`, do not assume `--slds-g-spacing-13` exists. Each category has a fixed scale defined by the design system.
|
|||
|
|
- **Invent semantic names** — There are no `--slds-g-spacing-page`, `--slds-g-font-heading`, or `--slds-g-shadow-modal` hooks. Hooks are numeric, not semantic.
|
|||
|
|
|
|||
|
|
**When unsure whether a hook exists:** Run the linter (`npx @salesforce-ux/slds-linter@latest lint --fix .`). It will suggest valid hooks for flagged values. If the linter doesn't flag a value or doesn't suggest a hook, leave it hardcoded.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Table of Contents
|
|||
|
|
|
|||
|
|
- [Spacing Hooks](#spacing-hooks)
|
|||
|
|
- [Sizing Hooks](#sizing-hooks)
|
|||
|
|
- [Typography Hooks](#typography-hooks)
|
|||
|
|
- [Border Width Hooks](#border-width-hooks)
|
|||
|
|
- [Border Radius Hooks](#border-radius-hooks)
|
|||
|
|
- [Shadow Hooks](#shadow-hooks)
|
|||
|
|
- [Uplift Decision Tree](#uplift-decision-tree--non-color)
|
|||
|
|
- [Common Mistakes](#common-mistakes)
|
|||
|
|
- [Accessibility Notes](#accessibility-notes)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Spacing Hooks
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-spacing-*`
|
|||
|
|
**Use for:** `margin`, `padding`, `gap`, `row-gap`, `column-gap`
|
|||
|
|
**Do NOT use for:** `width`, `height`, or other dimension properties (use sizing hooks)
|
|||
|
|
|
|||
|
|
**Scale range: 1–12.** There is no `--slds-g-spacing-13` or higher. If a value exceeds 5rem/80px, leave it hardcoded.
|
|||
|
|
|
|||
|
|
### Density-Aware Spacing
|
|||
|
|
|
|||
|
|
For components that adapt between comfy and compact display density, use density-aware variants:
|
|||
|
|
|
|||
|
|
| Hook Pattern | Applies To |
|
|||
|
|
|---|---|
|
|||
|
|
| `--slds-g-spacing-var-*` | All sides (margin, padding) |
|
|||
|
|
| `--slds-g-spacing-var-block-*` | Vertical only (top/bottom) |
|
|||
|
|
| `--slds-g-spacing-var-inline-*` | Horizontal only (left/right) |
|
|||
|
|
|
|||
|
|
Use density-aware hooks for data tables, forms, cards, tabs, and navigation components that need to respond to the user's density preference.
|
|||
|
|
|
|||
|
|
### Examples
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* Before */
|
|||
|
|
.card-body { padding: 1rem; }
|
|||
|
|
.list-item { margin-bottom: 0.5rem; }
|
|||
|
|
.grid { gap: 1.5rem; }
|
|||
|
|
|
|||
|
|
/* After — hook names come from the linter, not guesswork */
|
|||
|
|
.card-body { padding: var(--slds-g-spacing-4, 1rem); }
|
|||
|
|
.list-item { margin-bottom: var(--slds-g-spacing-2, 0.5rem); }
|
|||
|
|
.grid { gap: var(--slds-g-spacing-5, 1.5rem); }
|
|||
|
|
|
|||
|
|
/* Multi-value shorthand */
|
|||
|
|
.button { padding: var(--slds-g-spacing-2, 0.5rem) var(--slds-g-spacing-4, 1rem); }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Sizing Hooks
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-sizing-*`
|
|||
|
|
**Use for:** `width`, `height`, `min-width`, `max-width`, `min-height`, `max-height`
|
|||
|
|
**Do NOT use for:** `margin`, `padding`, `gap` (use spacing hooks)
|
|||
|
|
**Scale range: 1–16.** There is no `--slds-g-sizing-17` or higher.
|
|||
|
|
|
|||
|
|
### Examples
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* Before */
|
|||
|
|
.icon { width: 32px; height: 32px; }
|
|||
|
|
|
|||
|
|
/* After */
|
|||
|
|
.icon { width: var(--slds-g-sizing-9, 32px); height: var(--slds-g-sizing-9, 32px); }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Typography Hooks
|
|||
|
|
|
|||
|
|
### Font Scale
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-font-scale-*` (and `--slds-g-font-size-base` for 13px)
|
|||
|
|
**Use for:** `font-size`
|
|||
|
|
**Scale range: neg-4 through 10**, plus `base` (0.8125rem/13px). Negative values (`neg-1` to `neg-4`) are for small/caption text. There is no `--slds-g-font-scale-11` or higher.
|
|||
|
|
|
|||
|
|
Density-aware variant: `--slds-g-font-scale-var-*` (also 1–10) — adapts between comfy and compact.
|
|||
|
|
|
|||
|
|
### Font Weight
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-font-weight-*`
|
|||
|
|
**Use for:** `font-weight`
|
|||
|
|
**Scale range: 1–7.** Maps to CSS weight values 100–700. There is no `--slds-g-font-weight-8` or higher.
|
|||
|
|
|
|||
|
|
**Weight pairing guidance in SLDS 2:**
|
|||
|
|
- Display text (large scale) → lighter weight
|
|||
|
|
- Titles/headings → regular weight
|
|||
|
|
- Buttons/small body titles → semi-bold weight
|
|||
|
|
- Inline emphasis within body → bold weight (sparingly)
|
|||
|
|
|
|||
|
|
### Line Height
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-font-lineheight-*`
|
|||
|
|
**Use for:** `line-height`
|
|||
|
|
**Scale range: 1–6.** Values range from 1 to 2. There is no `--slds-g-font-lineheight-7` or higher.
|
|||
|
|
|
|||
|
|
### Font Family
|
|||
|
|
|
|||
|
|
| Hook | Use Case |
|
|||
|
|
|---|---|
|
|||
|
|
| `--slds-g-font-family` | Default font family |
|
|||
|
|
| `--slds-g-font-family-base` | Base font family |
|
|||
|
|
| `--slds-g-font-family-monospace` | Code snippets |
|
|||
|
|
|
|||
|
|
### Content Width
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-sizing-content-*` and `--slds-g-sizing-heading-*`
|
|||
|
|
**Use for:** `max-width` on text containers (uses `ch` units for readable line lengths)
|
|||
|
|
**Scale range:** `content` 1–3, `heading` 1–3.
|
|||
|
|
|
|||
|
|
### Typography Examples
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* Before */
|
|||
|
|
.title { font-size: 18px; font-weight: bold; line-height: 1.25; }
|
|||
|
|
.body { font-size: 14px; font-weight: normal; line-height: 1.5; }
|
|||
|
|
|
|||
|
|
/* After — let the linter confirm the correct scale numbers */
|
|||
|
|
.title {
|
|||
|
|
font-size: var(--slds-g-font-scale-4, 18px);
|
|||
|
|
font-weight: var(--slds-g-font-weight-4, bold);
|
|||
|
|
line-height: var(--slds-g-font-lineheight-2, 1.25);
|
|||
|
|
}
|
|||
|
|
.body {
|
|||
|
|
font-size: var(--slds-g-font-scale-1, 14px);
|
|||
|
|
font-weight: var(--slds-g-font-weight-4, normal);
|
|||
|
|
line-height: var(--slds-g-font-lineheight-4, 1.5);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Border Width Hooks
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-sizing-border-*`
|
|||
|
|
**Use for:** `border-width`, `border`, `border-top`, etc. (the width component)
|
|||
|
|
**Scale range: 1–4.** Maps to 1px–4px. There is no `--slds-g-sizing-border-5` or higher.
|
|||
|
|
|
|||
|
|
Border widths are NOT density-aware — they stay constant regardless of comfy/compact settings.
|
|||
|
|
|
|||
|
|
**SLDS 2 philosophy:** Use borders sparingly. Prefer spacing or shadows for visual separation. Use borders purposefully for structure, interactivity indication, and state communication.
|
|||
|
|
|
|||
|
|
### Examples
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* Before */
|
|||
|
|
.input { border: 1px solid #ccc; }
|
|||
|
|
|
|||
|
|
/* After */
|
|||
|
|
.input { border: var(--slds-g-sizing-border-1, 1px) solid var(--slds-g-color-border-2, #ccc); }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Border Radius Hooks
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-radius-border-*`
|
|||
|
|
**Use for:** `border-radius`
|
|||
|
|
**Scale range: 1–4** plus special values `circle` and `pill`. There is no `--slds-g-radius-border-5` or higher.
|
|||
|
|
|
|||
|
|
Choose radius by **component type**, not by matching px values. The hook resolves to the design-system value; the original value is preserved as fallback only.
|
|||
|
|
|
|||
|
|
| Hook | Components |
|
|||
|
|
|---|---|
|
|||
|
|
| `--slds-g-radius-border-1` | Badges, checkboxes |
|
|||
|
|
| `--slds-g-radius-border-2` | Text inputs, comboboxes, text areas, tooltips |
|
|||
|
|
| `--slds-g-radius-border-3` | Menus, popovers |
|
|||
|
|
| `--slds-g-radius-border-4` | Cards, modals, docked composers |
|
|||
|
|
| `--slds-g-radius-border-circle` | Buttons, button icons, avatars, radios, pills |
|
|||
|
|
| `--slds-g-radius-border-pill` | Pill-shaped elements |
|
|||
|
|
|
|||
|
|
Border radius hooks are NOT density-aware.
|
|||
|
|
|
|||
|
|
### Examples
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* Before */
|
|||
|
|
.card { border-radius: 8px; }
|
|||
|
|
.button { border-radius: 50%; }
|
|||
|
|
|
|||
|
|
/* After — chosen by component type, not px value */
|
|||
|
|
.card { border-radius: var(--slds-g-radius-border-4, 8px); }
|
|||
|
|
.button { border-radius: var(--slds-g-radius-border-circle, 50%); }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Shadow Hooks
|
|||
|
|
|
|||
|
|
**Prefix:** `--slds-g-shadow-*`
|
|||
|
|
**Use for:** `box-shadow`
|
|||
|
|
**Scale range: 1–6.** Directional variants (`-block-start-*`, `-block-end-*`, `-inline-start-*`, `-inline-end-*`) use range **1–4**. Focus variants (`-outline-focus-*`, `-outset-focus-*`, `-inset-focus-*`, `-inset-inverse-focus-*`) only have **1**.
|
|||
|
|
|
|||
|
|
Match shadow depth to the element's stacking order — higher shadows for elements visually above others:
|
|||
|
|
|
|||
|
|
| Hook | Components |
|
|||
|
|
|---|---|
|
|||
|
|
| `--slds-g-shadow-1` | Page headers, joined tables, filter panels, dropdowns, inline edit, slider handles |
|
|||
|
|
| `--slds-g-shadow-2` | Menus, docked form footer, docked utility bar, color picker, notifications |
|
|||
|
|
| `--slds-g-shadow-3` | Panels, docked composer, tooltips, toasts |
|
|||
|
|
| `--slds-g-shadow-4` | Modals, popovers, App Launcher |
|
|||
|
|
|
|||
|
|
### Directional Shadows
|
|||
|
|
|
|||
|
|
For components positioned against screen edges:
|
|||
|
|
|
|||
|
|
| Hook Pattern | Direction |
|
|||
|
|
|---|---|
|
|||
|
|
| `--slds-g-shadow-block-start-*` | Upward |
|
|||
|
|
| `--slds-g-shadow-block-end-*` | Downward (inherits from base) |
|
|||
|
|
| `--slds-g-shadow-inline-start-*` | Left |
|
|||
|
|
| `--slds-g-shadow-inline-end-*` | Right |
|
|||
|
|
|
|||
|
|
### Focus Shadows
|
|||
|
|
|
|||
|
|
| Hook Pattern | Use Case |
|
|||
|
|
|---|---|
|
|||
|
|
| `--slds-g-shadow-outline-focus-*` | Simple outline focus |
|
|||
|
|
| `--slds-g-shadow-outset-focus-*` | Double ring outset focus (white inner, brand outer) |
|
|||
|
|
| `--slds-g-shadow-inset-focus-*` | Single ring inset focus |
|
|||
|
|
| `--slds-g-shadow-inset-inverse-focus-*` | Double ring inset focus (brand inner, white outer) |
|
|||
|
|
|
|||
|
|
**SLDS 2 philosophy:** Don't apply shadows to base-level components that sit on a surface without covering other components.
|
|||
|
|
|
|||
|
|
### Examples
|
|||
|
|
|
|||
|
|
```css
|
|||
|
|
/* Before */
|
|||
|
|
.modal { box-shadow: 0 4px 8px rgba(0,0,0,0.1); }
|
|||
|
|
.dropdown { box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
|
|||
|
|
|
|||
|
|
/* After */
|
|||
|
|
.modal { box-shadow: var(--slds-g-shadow-4, 0 4px 8px rgba(0,0,0,0.1)); }
|
|||
|
|
.dropdown { box-shadow: var(--slds-g-shadow-1, 0 2px 4px rgba(0,0,0,0.1)); }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Uplift Decision Tree — Non-Color
|
|||
|
|
|
|||
|
|
When the linter flags a non-color hardcoded value, follow this process:
|
|||
|
|
|
|||
|
|
### Step 1: Run the Linter First
|
|||
|
|
|
|||
|
|
Always run `npx @salesforce-ux/slds-linter@latest lint --fix .` before manual fixes. The linter handles exact value-to-hook matches automatically. Only proceed to manual fixes for values the linter flags but cannot auto-fix.
|
|||
|
|
|
|||
|
|
### Step 2: Density-Aware or Standard?
|
|||
|
|
|
|||
|
|
Only use density-aware hooks if the original value was a variable density token:
|
|||
|
|
- `--lwc-varSpacingMedium` → `--slds-g-spacing-var-4`
|
|||
|
|
- `--lwc-spacingMedium` → `--slds-g-spacing-4` (non-variable, use standard hook)
|
|||
|
|
|
|||
|
|
### Step 3: No Exact Match — Should You Replace?
|
|||
|
|
|
|||
|
|
**Shadow:** If a shadow hook is nearly identical (e.g., offset differs by 1px), replace with the closest equivalent. Otherwise, leave as-is.
|
|||
|
|
|
|||
|
|
**Border Radius:** Replace by component type (see table above), not by px value. If the element doesn't match a known component type, leave hardcoded.
|
|||
|
|
|
|||
|
|
**Typography:** If between two scale values, use the closest. If far outside the available range, leave as-is.
|
|||
|
|
|
|||
|
|
**Spacing/Sizing:** If within 10% of a hook value, update to the closest hook. Otherwise leave as-is.
|
|||
|
|
|
|||
|
|
**Hardcoded numerical/structural values:** Never change or remove values like `width: 100%`, `height: 50%`, `max-width: 200px`, `flex: 1`, `height: auto`, `display: none`, `line-height: 1.5`, or `0`. These are layout and structural values, not candidates for hooks. Leave them exactly as they are in the source CSS.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Common Mistakes
|
|||
|
|
|
|||
|
|
1. **Inventing hooks that don't exist** — This is the most common and damaging mistake. Named hooks (`--slds-g-spacing-medium`) and out-of-range numbered hooks do not exist. Always verify with the linter.
|
|||
|
|
|
|||
|
|
2. **Confusing spacing and sizing** — Spacing is for margins/padding/gaps. Sizing is for width/height/dimensions. Using the wrong one makes the value density-unaware or disrupts the grid system.
|
|||
|
|
|
|||
|
|
3. **Replacing or removing hardcoded numerical values** — Never change `width: 100%`, `height: 50%`, `max-width: 200px`, `flex: 1`, `height: auto`, `display: none`, `line-height: 1.5`, or `0`. These are structural/layout values — do not replace them with hooks and do not remove them.
|
|||
|
|
|
|||
|
|
4. **Missing fallback values** — Always include the original value as fallback: `var(--slds-g-spacing-4, 1rem)`. Without fallbacks, the component breaks if the hook is unavailable.
|
|||
|
|
|
|||
|
|
5. **Ignoring density-aware variants** — For data-dense components (tables, forms, lists), use `--slds-g-spacing-var-*` and `--slds-g-font-scale-var-*` so spacing and text adapt to comfy/compact settings.
|
|||
|
|
|
|||
|
|
6. **Using `--slds-c-*` or `--slds-s-*` hooks** — Only `--slds-g-*` (global) hooks are valid for migration. Component and scoped hooks are not for direct use in CSS.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Accessibility Notes
|
|||
|
|
|
|||
|
|
### Touch Targets
|
|||
|
|
- Minimum 24x24 CSS pixels for pointer inputs (WCAG 2.2 Level AA)
|
|||
|
|
- Minimum 44x44 for touch inputs (industry standard)
|
|||
|
|
- Use spacing hooks for padding to achieve target sizes on interactive elements
|
|||
|
|
|
|||
|
|
### Typography Readability
|
|||
|
|
- Use body-level font scale or larger for primary body text
|
|||
|
|
- Default base font size (13px) is at the lower limit for comfortable reading
|
|||
|
|
- Use a line height of 1.5 as default for body text (WCAG 1.4.12)
|
|||
|
|
- Optimal line length: 45-75 characters (use content width hooks for max-width)
|
|||
|
|
|
|||
|
|
### Focus Visibility
|
|||
|
|
- Use appropriate border-width hooks for focus state borders
|
|||
|
|
- Use `--slds-g-shadow-outset-focus-*` for focus rings (double-ring pattern visible on any background)
|
|||
|
|
- Focus borders must maintain 3:1 minimum contrast with adjacent surfaces
|
|||
|
|
|
|||
|
|
### Border Contrast
|
|||
|
|
- Borders must maintain 3:1 contrast ratio with adjacent surfaces
|
|||
|
|
- Use higher-contrast border color hooks for interactive elements
|
|||
|
|
- Use lower-contrast border color hooks for decorative/non-interactive borders
|