@orkestrel/scaffold 0.0.65 → 0.0.67
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/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +58 -38
- package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +63 -33
- package/dist/host/agents/skills/enterprise-bootstrap/references/color-modes.md +131 -16
- package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +21 -13
- package/dist/host/agents/skills/enterprise-bootstrap/references/frontend-design.md +41 -46
- package/dist/host/agents/skills/enterprise-bootstrap/references/inputs.md +37 -29
- package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +51 -16
- package/dist/host/agents/skills/enterprise-bootstrap/references/responsive-layout.md +57 -7
- package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +11 -6
- package/dist/host/claude/agents/orkestrel.md +24 -24
- package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +1 -1
- package/dist/host/manifest.json +12 -12
- package/dist/host/scripts/codex.sh +0 -0
- package/dist/host/scripts/cursor.sh +0 -0
- package/dist/host/scripts/deps.sh +0 -0
- package/dist/host/scripts/ollama.sh +0 -0
- package/dist/src/core/index.cjs +8 -8
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.js +8 -8
- package/dist/src/core/index.js.map +1 -1
- package/package.json +8 -8
|
@@ -33,7 +33,7 @@ hand-roll before building one.
|
|
|
33
33
|
|
|
34
34
|
| Layer | File | Holds |
|
|
35
35
|
| -------------- | ----------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
36
|
-
| Operate | `SKILL.md` | Process,
|
|
36
|
+
| Operate | `SKILL.md` | Process, styling ladder, contrast bars, action rank, checklist |
|
|
37
37
|
| Design craft | [frontend-design.md](references/frontend-design.md) | Hierarchy, spacing, type, color, depth, imagery, signature, copy |
|
|
38
38
|
| Components | [components.md](references/components.md) | Bootstrap markup and enterprise selection notes |
|
|
39
39
|
| Inputs | [inputs.md](references/inputs.md) | Affordance, alternates, styling rung, and states per category |
|
|
@@ -44,8 +44,9 @@ hand-roll before building one.
|
|
|
44
44
|
| Instruments | [inspection.md](references/inspection.md) | Mechanical evidence contracts and rendered review criteria |
|
|
45
45
|
|
|
46
46
|
Take the operating rules here over a lookup example. Adapt example heading levels, action rank,
|
|
47
|
-
labels, and paint to the host surface. Move illustrative inline
|
|
48
|
-
ladder before shipping;
|
|
47
|
+
labels, and paint to the host surface. Move an illustrative inline declaration through the styling
|
|
48
|
+
ladder before shipping; its presence in a lookup is not an exemption. A declaration a lookup names
|
|
49
|
+
as a runtime producer is the exception, and only for the property that lookup names.
|
|
49
50
|
|
|
50
51
|
---
|
|
51
52
|
|
|
@@ -57,7 +58,7 @@ ladder before shipping; their presence in a lookup is not an exemption.
|
|
|
57
58
|
4. **Write framework-neutral markup** — semantic HTML plus Bootstrap classes. Wire behavior with the project's stack; in an SPA prefer framework-native Bootstrap wrappers over competing DOM ownership ([bootstrap-reference.md](references/bootstrap-reference.md) → JavaScript lifecycle).
|
|
58
59
|
5. **Keep this folder intact** so its relative links resolve. Install or vendor it wherever the tooling looks for skills; the paths are tooling-specific, the content is not.
|
|
59
60
|
6. **Use the installed Bootstrap.** Otherwise take the pinned CDN example from [bootstrap-reference.md](references/bootstrap-reference.md) → Quick start. Do not upgrade dependencies as a side effect of a visual pass.
|
|
60
|
-
7. **Apply this
|
|
61
|
+
7. **Apply this skill** to the work in its frontmatter. For a requested verdict, round, or campaign over an already rendering surface, use `orkestrel-polish-surface`; use this skill for the campaign's Bootstrap fixes.
|
|
61
62
|
|
|
62
63
|
---
|
|
63
64
|
|
|
@@ -78,10 +79,10 @@ Read [frontend-design.md](references/frontend-design.md) before setting a direct
|
|
|
78
79
|
visual decisions; the loop here owns their order.
|
|
79
80
|
|
|
80
81
|
1. **Ground** — state the subject, audience, single job, primary action, and existing constraints. Use real content; mark fixture data as such. Start with a feature, not a navigation shell.
|
|
81
|
-
2. **Plan** — record each region's narrow layout, expansion threshold, content/action parity, and overflow policy in a responsive contract. Render the primary task at 320 and 390 CSS px before expanding the shell. Settle reading order and grouping in low fidelity before paint, and hold color until the arrangement reads in grayscale (body surfaces, inherited text, weight, and spacing only). Reuse or define a compact system: **color families and surface ownership**, **type roles and scale**, **spacing and width roles**, **radius and elevation**, **a coherent signature where the brief calls for one**. Set personality
|
|
82
|
+
2. **Plan** — record each region's narrow layout, expansion threshold, content/action parity, and overflow policy in a responsive contract. Render the primary task at 320 and 390 CSS px before expanding the shell. Settle reading order and grouping in low fidelity before paint, and hold color until the arrangement reads in grayscale (body surfaces, inherited text, weight, and spacing only). Reuse or define a compact system: **color families and surface ownership**, **type roles and scale**, **spacing and width roles**, **radius and elevation**, **a coherent signature where the brief calls for one**. Set personality through these levers — typeface, primary color, radius family, and copy register — and hold each on every screen. Record changes, not a parallel system. Take each scale's Bootstrap source, shipped steps, and gaps from [bootstrap-reference.md](references/bootstrap-reference.md) → Define the working scales. State the settled layout in prose or a small wireframe before building it.
|
|
82
83
|
3. **Critique the plan** — reject unclear hierarchy, invented functionality, and interchangeable styling. Follow a pinned brief; otherwise take character from the subject rather than clustered AI defaults. Do not manufacture novelty inside an established product.
|
|
83
|
-
4. **Build** — implement the smallest useful flow and its data states, then refine the working feature. Use documented components and shipped utilities; map shared tokens once. Fix conflicting declarations rather than adding specificity. Extend the next feature after this one works.
|
|
84
|
-
5. **Critique the render** — complete the primary flow at narrow width first; then read task, hierarchy, grouping, type, contrast, states, and signature in order. Fix the earliest failure first. Remove a needless accessory if one exists; never remove useful information to meet a quota.
|
|
84
|
+
4. **Build** — implement the smallest useful flow and its data states, then refine the working feature. Use documented components and shipped utilities; map shared tokens once. Fix conflicting declarations rather than adding specificity. Revise the recorded plan when the render disproves it. Extend the next feature after this one works.
|
|
85
|
+
5. **Critique the render** — complete the primary flow at narrow width first; then read task, hierarchy, grouping, type, contrast, states, and signature in order. Fix the earliest failure first, then re-read the earlier criteria against the fixed render. Remove a needless accessory if one exists; never remove useful information to meet a quota.
|
|
85
86
|
|
|
86
87
|
Keep exploratory drafts private. Deliver the selected direction, the changes, and their evidence
|
|
87
88
|
limits, not every discarded variation.
|
|
@@ -90,7 +91,7 @@ limits, not every discarded variation.
|
|
|
90
91
|
snapshot. Use captures for visual claims and source to explain mechanisms; use interaction tests
|
|
91
92
|
for behavior. `.agents/orchestration.md` owns this law where present. Name the coverage and any
|
|
92
93
|
unverified state. Without a render-capable environment, report visual verification as open, never
|
|
93
|
-
as passed.
|
|
94
|
+
as passed.
|
|
94
95
|
|
|
95
96
|
**Mechanical proof.** Run applicable instruments in [inspection.md](references/inspection.md) with
|
|
96
97
|
their negative controls. Report population, reading, control result, and coverage. A control the
|
|
@@ -112,27 +113,41 @@ and captures are evidence, not fabricated mechanical tests or a beauty score.
|
|
|
112
113
|
|
|
113
114
|
### The styling ladder
|
|
114
115
|
|
|
115
|
-
Reach a rung only when the preceding one cannot express the need.
|
|
116
|
+
Reach a rung only when the preceding one cannot express the need. Cite a rung by its name, never by
|
|
117
|
+
its position.
|
|
116
118
|
|
|
117
|
-
1. **
|
|
118
|
-
2. **
|
|
119
|
-
3. **Bootstrap extension points.** Use component `--bs-{component}-*` variables or the Sass utilities API for a recurring system gap. Declare the role once, compile where required, and verify the emitted rule.
|
|
120
|
-
4. **
|
|
119
|
+
1. **Component rung — documented component structure.** Keep required elements, nesting, modifiers, behavior, and ARIA. Use optional headers, titles, and footers only when the content needs them; a component example is not a mandate to add empty chrome.
|
|
120
|
+
2. **Utility rung — shipped utilities.** Compose spacing, flex, sizing, text, border, and color classes from [utilities.md](references/utilities.md). Verify extensions exist in the loaded build before authoring them.
|
|
121
|
+
3. **Extension rung — Bootstrap extension points.** Use component `--bs-{component}-*` variables or the Sass utilities API for a recurring system gap. Declare the role once, compile where required, and verify the emitted rule.
|
|
122
|
+
4. **Authored rung — developer-authorized custom CSS.** Propose what Bootstrap cannot express and why. Take this rung unasked only under [inspection.md](references/inspection.md) → When an authored rule is already earned.
|
|
121
123
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
Resolve a conflict at the rung that owns it. Utilities may carry `!important`, so read the winning
|
|
125
|
+
declaration in the shipped cascade and remove the conflicting class before escalating selector
|
|
126
|
+
specificity. A class selector stays a class selector whatever its name.
|
|
127
|
+
|
|
128
|
+
**Where an authored rule lives.** Put every authored rule in the project's stylesheet and token
|
|
129
|
+
layer. A standalone HTML deliverable carries that stylesheet as one `<style>` block in `<head>` —
|
|
130
|
+
tokens and declared roles, before any markup. That block is the project stylesheet.
|
|
131
|
+
|
|
132
|
+
Never write a `style` attribute on authored markup, and never open a second `<style>` block beside
|
|
133
|
+
a component or scoped to one. This rule fixes a location and nothing else: inline CSS and authored
|
|
134
|
+
rules participate in the cascade normally, and a runtime producer named in
|
|
135
|
+
[inspection.md](references/inspection.md) → Style escapes writes its own declaration.
|
|
136
|
+
|
|
137
|
+
**What an authored rule may contain** is a separate rule, and the styling ladder owns it. Reach the
|
|
138
|
+
authored rung only when the component, utility, and extension rungs cannot express the need. Do not
|
|
139
|
+
duplicate a shipped utility, and keep raw values in declared primitive definitions rather than in
|
|
140
|
+
component paint.
|
|
126
141
|
|
|
127
142
|
### Hierarchy & actions
|
|
128
143
|
|
|
129
|
-
| Rank or meaning | Typical choice
|
|
130
|
-
| --------------- |
|
|
131
|
-
| Primary | `btn btn-primary` — at most one dominant action per active task region
|
|
132
|
-
| Secondary |
|
|
133
|
-
| Tertiary | `btn btn-link` for an action; a real link for navigation
|
|
134
|
-
| Destructive | Rank first; strong `btn-danger` for the final destructive commit
|
|
135
|
-
| Status | Quiet badge or alert treatment; icon + color + word
|
|
144
|
+
| Rank or meaning | Typical choice |
|
|
145
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
146
|
+
| Primary | `btn btn-primary` — at most one dominant action per active task region |
|
|
147
|
+
| Secondary | `btn-outline-secondary` with `--bs-btn-color: var(--bs-emphasis-color)` set once at the theme root (the stock label is 3.3:1 on the dark body), or `btn-secondary` |
|
|
148
|
+
| Tertiary | `btn btn-link` for an action; a real link for navigation |
|
|
149
|
+
| Destructive | Rank first; strong `btn-danger` for the final destructive commit |
|
|
150
|
+
| Status | Quiet badge or alert treatment; icon + color + word |
|
|
136
151
|
|
|
137
152
|
Choose rank before hue. Do not make every action solid or every destructive action dominant.
|
|
138
153
|
Outline and link-style controls are allowed only when their text, boundary or state cue, and focus
|
|
@@ -146,9 +161,11 @@ not lower the required friction. Draw a textless status mark as an icon glyph, n
|
|
|
146
161
|
|
|
147
162
|
### Surfaces, color, contrast
|
|
148
163
|
|
|
149
|
-
- **Hold
|
|
164
|
+
- **Hold these bars — this section owns them.** ≥ 4.5:1 for all information-bearing text, including large text, captions, and metadata; ≥ 3:1 for meaningful textless marks and state/focus chrome. The text floor is deliberately stricter than WCAG's large-text exception. Measure every declared theme and reached state; do not generalize one reading to all surfaces. A ratio quoted anywhere in this skill is a stock Bootstrap reading and bounds that stock theme alone — the bars are the policy, the readings are not.
|
|
150
165
|
- **Inherit ordinary text.** When content owns no background, add no foreground override. Prefer `bg-body`, `bg-body-secondary`, `bg-body-tertiary`, and `bg-*-subtle` for quiet surfaces; do not automatically add a text-color utility to them. Follow [color-modes.md](references/color-modes.md) for exceptions and component-owned colors.
|
|
151
|
-
- **
|
|
166
|
+
- **Pair like with like.** Adaptive text on adaptive surfaces (`text-body*` and `text-*-emphasis` on `bg-body*` and `bg-*-subtle`); fixed text on fixed fills (`text-bg-*`, a component's own foreground, or a `data-bs-theme` scope that also carries `text-body` — a scope changes variables only, and plain text inherits the outer mode's painted color). Treat a mixed pair as unproven and measure it in each declared mode: `bg-light` with inherited text, `text-white` on `bg-body`, `text-primary` on the dark body, and a stock `btn-outline-secondary` label in dark mode each fail one stock mode, while inherited text on `bg-primary` fails light and dark alike. Replace `bg-light`, `bg-white`, and `text-dark` on adaptive surfaces because they are fixed ([color-modes.md](references/color-modes.md) → Fixed and adaptive classes).
|
|
167
|
+
- **Clear a deprecated class on its deprecation, not on a contrast reading.** 5.3 deprecates `text-muted`, `navbar-light`, `navbar-dark`, `dropdown-menu-dark`, `btn-close-white`, and `carousel-dark`. `text-muted` still resolves through the adaptive secondary color, so it pairs correctly and is a deprecation to clear; the `navbar-*`, `dropdown-menu-dark`, `btn-close-white`, and `carousel-dark` classes give way to a `data-bs-theme` scope.
|
|
168
|
+
- **Keep supporting text readable.** Start with inherited color, spacing, and weight. Use `text-body-secondary` for a deliberate secondary tier — it clears 4.5:1 on every stock body surface in light and dark — not for every caption. `text-body-tertiary` is body color at 50 % alpha and measures 3.0–4.1:1 on those stock surfaces: decoration or disabled only, never a caption someone reads. Any further readable tier is a declared opaque token, measured on the surface it sits on. Never quiet text with opacity, and do not carry a neutral secondary tier blindly onto a colored fill; inherit its tested foreground first, using a scoped opaque same-hue tier only when needed ([color-modes.md](references/color-modes.md) → Text tiers).
|
|
152
169
|
- **Pair intentional solid surfaces; preserve selected foregrounds.** Let the owning component set its foreground and background, or use a tested solid pair. Do not recolor ordinary children. Keep status encoded by icon and word and capture the selected state.
|
|
153
170
|
- **Inside subtle fills, measure the children against that fill.** Badge, button, and caption recipes need their own readings; a page-background result does not transfer into a card or alert.
|
|
154
171
|
- **Exempt disabled controls from the contrast bars**, but visibly neutralize an unavailable destructive action and explain why with `aria-describedby`; `title` may supplement, never replace, the explanation.
|
|
@@ -161,7 +178,7 @@ Take [responsive-layout.md](references/responsive-layout.md) as the layout contr
|
|
|
161
178
|
primary task, reading order, and access to information at every width. A contained horizontal
|
|
162
179
|
table can pass document-overflow checks and still fail the task; inspect both.
|
|
163
180
|
|
|
164
|
-
- Choose density for the task. Start each gap one step too large, render, and step down; compress where throughput or comparison requires it, not because the default felt cramped.
|
|
181
|
+
- Choose density for the task. Start each gap one step too large, render, and step down; compress where throughput or comparison requires it, not because the default felt cramped. Hold every target to the floor in [bootstrap-reference.md](references/bootstrap-reference.md) → WCAG 2.2 requirements for app UI, which owns the target dimensions.
|
|
165
182
|
- Take compact controls together across a row: `btn-sm`, `form-control-sm`, `form-select-sm`, and `input-group-sm`. Do not shrink body text or targets to force one-row layouts.
|
|
166
183
|
- Keep inter-group gaps larger than internal gaps. Bound forms, rails, and prose by content with a maximum width; let comparison tables use the width they need. Use percentage columns only where elements must scale together — a `col-*` login card or `col-3` sidebar changes width at every breakpoint ([bootstrap-reference.md](references/bootstrap-reference.md) → Breakpoints & layout).
|
|
167
184
|
- Use `.card` where an independent group earns containment. Try spacing and type before more borders, fills, or shadows. Keep elevation tied to layering, not every available box.
|
|
@@ -181,18 +198,19 @@ table can pass document-overflow checks and still fail the task; inspect both.
|
|
|
181
198
|
- Choose the affordance by what the person is asked for in [inputs.md](references/inputs.md), and draw its fixed state set. Keep read-only/edit geometry stable and preserve the non-drag path for uploads.
|
|
182
199
|
- Give every field a visible label or `.form-floating`, never placeholder-only. Removing redundant labels on displayed data does not apply to inputs. Naming a form does not name its individual controls.
|
|
183
200
|
- Keep label, control, help, and error closer to each other than to the next field group. Use extra columns for genuinely related fields or supporting explanation, not to fill a wide canvas.
|
|
184
|
-
- Validate on blur, re-validate error fields on input, and re-check on submit. Keep submit enabled;
|
|
201
|
+
- Validate on blur, re-validate error fields on input, and re-check on submit. Keep submit enabled while fields are invalid; a disabled submit hides what is wrong. While a submit is in flight, mark the control busy and refuse a second submit — that pending block is a different state, and this rule does not bar it. Show a focusable error summary and linked inline feedback (`aria-describedby`, `aria-invalid`).
|
|
185
202
|
- Take validation mechanics, autosave, and multi-step rules from [bootstrap-reference.md](references/bootstrap-reference.md) → Forms in production, Wizards & multi-step forms.
|
|
186
203
|
|
|
187
204
|
### When custom CSS is justified
|
|
188
205
|
|
|
189
|
-
Exhaust rungs
|
|
190
|
-
that would satisfy it. A desire for a signature does not waive the
|
|
206
|
+
Exhaust the component, utility, and extension rungs before proposing a custom rule. Name the unmet
|
|
207
|
+
requirement and the smallest rule that would satisfy it. A desire for a signature does not waive the
|
|
208
|
+
styling ladder.
|
|
191
209
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
210
|
+
Wait for developer authorization. [inspection.md](references/inspection.md) → When an authored rule
|
|
211
|
+
is already earned owns the one exception and every condition that opens it; read that section rather
|
|
212
|
+
than judging a shorter copy here. An unavailable Sass build is not permission to silently invent a
|
|
213
|
+
second CSS system.
|
|
196
214
|
|
|
197
215
|
When authorized, or when that exception opens:
|
|
198
216
|
|
|
@@ -206,7 +224,7 @@ When authorized, or when that exception opens:
|
|
|
206
224
|
## Accessibility baseline
|
|
207
225
|
|
|
208
226
|
- Give the page a skip link, landmarks, and ordered headings; visual size does not dictate heading level.
|
|
209
|
-
- Name icon-only controls and
|
|
227
|
+
- Name icon-only controls and hold every target to the floor in [bootstrap-reference.md](references/bootstrap-reference.md) → WCAG 2.2 requirements for app UI. Preserve visible labels within accessible names.
|
|
210
228
|
- Use `aria-current` for the current navigation item, `aria-selected` for selectable tabs, and native checked state for checkboxes/radios. Do not apply one selection attribute to every widget.
|
|
211
229
|
- Wire disclosures with `aria-expanded` and `aria-controls`; wire help/errors with `aria-describedby` and invalid fields with `aria-invalid`.
|
|
212
230
|
- Match announcements to urgency: polite status for routine async results, alerts for urgent failures. Do not infer urgency solely from an alert's visual styling.
|
|
@@ -234,16 +252,18 @@ Progress:
|
|
|
234
252
|
- [ ] Typeface, primary color, radius family, and copy register set once and held; arrangement read in grayscale before hue
|
|
235
253
|
- [ ] Type sizes in `rem` from the scale or its generated steps; no `em` sizes, nested `.small`, or off-scale spacing
|
|
236
254
|
- [ ] Components and utilities resolved in the shipped build; input affordances and states taken from their references
|
|
237
|
-
- [ ] Styling ladder held; no
|
|
255
|
+
- [ ] Styling ladder held; no `style` attribute, no component-scoped `<style>` block, no unearned utility duplication; a standalone HTML deliverable carries its one project stylesheet in `<head>`
|
|
238
256
|
- [ ] Tokens mapped through semantics to components; literals confined to declared primitives
|
|
239
257
|
- [ ] Ordinary/subtle content inherits; solid exceptions own their pair; no fixed leaf color conceals a mode failure
|
|
258
|
+
- [ ] Every text/background pair is adaptive-on-adaptive or fixed-on-fixed; fixed fills carry `text-bg-*`, their component's foreground, or a `data-bs-theme` scope with `text-body` on the same element; no `bg-light`, `bg-white`, or `text-dark` on adaptive surfaces
|
|
259
|
+
- [ ] Deprecated classes cleared on their deprecation: `text-muted`, `navbar-light`, `navbar-dark`, `dropdown-menu-dark`, `btn-close-white`, `carousel-dark`
|
|
240
260
|
- [ ] Secondary tier is `text-body-secondary` or a declared opaque token; no opacity or unreadable tertiary tone; secondary text on colored surfaces measured rather than assumed
|
|
241
|
-
- [ ]
|
|
261
|
+
- [ ] Every declared mode transition, supported nested scopes, and overlay mounts tested without rebuilding the UI
|
|
242
262
|
- [ ] Primary action clear; supporting content readable; destructive rank and friction both correct
|
|
243
263
|
- [ ] Group spacing unambiguous; widths content-led; type/baseline/line length suitable
|
|
244
264
|
- [ ] All data states built; first-use and filtered-empty distinct; errors recoverable; no invented progress
|
|
245
265
|
- [ ] Images bounded and legible; depth serves layering; accents, tints, and shadows each earn their place; no needless accessories
|
|
246
|
-
- [ ] Contrast measured in
|
|
266
|
+
- [ ] Contrast measured in every declared theme and reached state against the bars in § Surfaces, color, contrast
|
|
247
267
|
- [ ] Keyboard, labels, announcements, targets, reduced motion, and non-drag paths checked
|
|
248
268
|
- [ ] Forms retain visible labels, blur/submit validation, and summary + inline errors
|
|
249
269
|
- [ ] Responsive contract recorded; primary task works at 320/390 CSS px before wide-screen enhancement
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Bootstrap 5 Deep Reference — Theming, Forms, JS, Accessibility, Enterprise Patterns
|
|
2
2
|
|
|
3
|
-
> Part of the `enterprise-bootstrap`
|
|
3
|
+
> Part of the `enterprise-bootstrap` skill. Bootstrap **5.3.x**.
|
|
4
4
|
> Component markup lookups: [components.md](components.md). Utility classes: [utilities.md](utilities.md).
|
|
5
5
|
> This file holds what those do not: setup, color modes, theming/tokens, forms in
|
|
6
6
|
> production, the JS lifecycle, accessibility depth, and enterprise app patterns.
|
|
@@ -49,6 +49,8 @@ Pinned CDN example (5.3.8). Prefer the installed compatible version; this is not
|
|
|
49
49
|
|
|
50
50
|
## Breakpoints & Layout
|
|
51
51
|
|
|
52
|
+
Stock 5.3.8 values: breakpoints `sm` 576 · `md` 768 · `lg` 992 · `xl` 1200 · `xxl` 1400 px (`min-width`; `xs` has no infix); `.container` maxima 540 · 720 · 960 · 1140 · 1320 px; gutter and container padding 1.5 rem (296 px of content at 320 px). Only `d`, `flex`, `justify-content`, `align-*`, `order`, `float`, `gap`, spacing, text alignment, and `object-fit` utilities ship breakpoint infixes. Generate a missing responsive role only where a `$utilities` entry owns the property, per [Utilities API](#utilities-api). Full inventory and recipes: [responsive-layout.md](responsive-layout.md) → Bootstrap's responsive surface.
|
|
53
|
+
|
|
52
54
|
Start with the feature's content and narrow layout, then choose its container and breakpoints.
|
|
53
55
|
Take the region contract, content parity, and test matrix from [responsive-layout.md](responsive-layout.md).
|
|
54
56
|
Use fluid columns for content that needs to scale together; keep rails, forms, and reading measures
|
|
@@ -143,7 +145,7 @@ states, and resolve aliases at the scope where they must change. Take the constr
|
|
|
143
145
|
|
|
144
146
|
Reuse the installed theme and its scales first. Declare new values only for a role the feature
|
|
145
147
|
needs; refine one shared definition instead of accumulating per-component exceptions. Every
|
|
146
|
-
system
|
|
148
|
+
system in the following table has a Bootstrap source, a utility, and a known gap; extend the source, never the
|
|
147
149
|
markup.
|
|
148
150
|
|
|
149
151
|
| System | Sass source | Utility | Stock steps (default root) | Gap |
|
|
@@ -164,8 +166,8 @@ markup.
|
|
|
164
166
|
dark text shades in real components, then fill the gaps. Use HSL when it helps tune related
|
|
165
167
|
shades; keep the project's existing format. Review fixed shade pairs in each theme rather than
|
|
166
168
|
generating a new `lighten`, `darken`, or `color-mix` result at each use site. Stock ramps and
|
|
167
|
-
triads are tint/shade mixes with a fixed hue; override the
|
|
168
|
-
variables per brand hue, and the
|
|
169
|
+
triads are tint/shade mixes with a fixed hue; override the shade variables and triad
|
|
170
|
+
variables per brand hue, and the greys as one temperature-matched set
|
|
169
171
|
([color-modes.md](color-modes.md) → Extend the theme).
|
|
170
172
|
- **Type:** display/body/utility roles, finite `rem` sizes, working weights, and line-height per
|
|
171
173
|
role. Roles may share a font. RFS scales sizes above 1.25 rem down below a 1200 px viewport
|
|
@@ -175,7 +177,7 @@ markup.
|
|
|
175
177
|
- **Space and size:** internal, group, panel, and section gaps; control sizes; reading/form widths;
|
|
176
178
|
rail width. Start with Bootstrap's shipped scale. Add a missing step through the utilities API
|
|
177
179
|
only where the adjacent steps cannot express the intended relationship. Button sizes already
|
|
178
|
-
scale padding faster than font (4/8 px at 14 px, 6/12 at 16, 8/16 at 20); use the
|
|
180
|
+
scale padding faster than font (4/8 px at 14 px, 6/12 at 16, 8/16 at 20); use the shipped
|
|
179
181
|
sizes rather than deriving one with `em` padding.
|
|
180
182
|
- **Radius and elevation:** a small consistent family, assigned to real component/layer roles.
|
|
181
183
|
Set `$border-radius` once and let components inherit it; do not hand-mix `rounded-*` per
|
|
@@ -189,13 +191,13 @@ that boundary; [frontend-design.md](frontend-design.md) owns the visual choices.
|
|
|
189
191
|
|
|
190
192
|
### Elevation and depth
|
|
191
193
|
|
|
192
|
-
|
|
193
|
-
(`0 .5rem 1rem` at .15), `--bs-box-shadow-lg` (`0 1rem 3rem` at .175)
|
|
194
|
+
Bootstrap ships `--bs-box-shadow-sm` (`0 .125rem .25rem` at .075), `--bs-box-shadow`
|
|
195
|
+
(`0 .5rem 1rem` at .15), and `--bs-box-shadow-lg` (`0 1rem 3rem` at .175), plus
|
|
194
196
|
`--bs-box-shadow-inset`. Assign by z-position: `sm` for raised cards and controls, base for
|
|
195
197
|
floating menus and a dragged item, `lg` for dialogs. Stock dropdowns, popovers, toasts, and
|
|
196
198
|
modals all sit on `--bs-box-shadow` (modal: `-sm` below 576 px), which puts a blocking dialog at
|
|
197
|
-
dropdown elevation. Lift it at rung
|
|
198
|
-
wins the `sm`-up media rule:
|
|
199
|
+
dropdown elevation. Lift it at the extension rung, in the project stylesheet after Bootstrap's so
|
|
200
|
+
the rule wins the `sm`-up media rule:
|
|
199
201
|
|
|
200
202
|
```css
|
|
201
203
|
.modal {
|
|
@@ -210,10 +212,10 @@ and every consumer follows.
|
|
|
210
212
|
`$enable-shadows: true` (off by default) paints light-from-above on controls: buttons take
|
|
211
213
|
`inset 0 1px 0 rgba(#fff, .15), 0 1px 1px rgba(#000, .075)` (lit top edge, tight cast shadow),
|
|
212
214
|
inputs `inset 0 1px 2px rgba(#000, .075)` (recessed), and an active button `inset 0 3px 5px`
|
|
213
|
-
(pressed). Enable it when the direction wants tactile controls, and verify
|
|
215
|
+
(pressed). Enable it when the direction wants tactile controls, and verify every declared theme; the alphas
|
|
214
216
|
are fixed white and black. Without the flag the `box-shadow` mixin emits nothing, so
|
|
215
|
-
`--bs-btn-box-shadow` and `--bs-box-shadow-inset` have no consumer and
|
|
216
|
-
nothing; the recipe is then a proposed rule.
|
|
217
|
+
`--bs-btn-box-shadow` and `--bs-box-shadow-inset` have no consumer and an extension-rung override
|
|
218
|
+
does nothing; the recipe is then a proposed rule.
|
|
217
219
|
|
|
218
220
|
Flat depth: a `bg-body` panel on `bg-body-tertiary` reads raised and `bg-body-secondary` inside
|
|
219
221
|
`bg-body` reads inset, both mode-adaptive with no shadow. A hard offset shadow is a `$box-shadow`
|
|
@@ -233,6 +235,8 @@ Then `rounded-circle border border-3 ring-body`.
|
|
|
233
235
|
|
|
234
236
|
### The CSS-variables-only path (no Sass build)
|
|
235
237
|
|
|
238
|
+
When the deliverable is one self-contained HTML file, the project stylesheet is a single `<style>` block in `<head>` — tokens, declared role utilities, and extension-rung variable overrides, in that order — loaded after the Bootstrap `<link>` so equal-specificity rules win by source order. It is still one stylesheet: no `style` attribute on authored markup and no second `<style>` block beside a component ([SKILL.md](../SKILL.md) → The styling ladder owns that placement rule).
|
|
239
|
+
|
|
236
240
|
Use native components and adaptive utilities before adding overrides. For a recurring component
|
|
237
241
|
surface role, use its local variable rather than repainting the whole component. This optional
|
|
238
242
|
project-defined class changes the card background without assigning a foreground:
|
|
@@ -302,10 +306,18 @@ $utilities: map-merge(
|
|
|
302
306
|
|
|
303
307
|
Remove with `map-remove($utilities, "width")` or set the key to `null`. This is the sanctioned answer when the shipped scale is missing a step (for example, a `vh-50` the design truly needs).
|
|
304
308
|
|
|
309
|
+
**`responsive: true` reaches a utility family and nothing else.** It adds breakpoint infixes to one
|
|
310
|
+
entry in the `$utilities` map, so it generates `w-md-auto` from the `width` entry and `ls-lg-tight`
|
|
311
|
+
from an added `letter-spacing` entry. A component threshold (`navbar-expand-*`, `offcanvas-*`,
|
|
312
|
+
`table-responsive-*`, `modal-fullscreen-*-down`), a grid class, and a helper (`visually-hidden`,
|
|
313
|
+
`stretched-link`, `ratio`, `vstack`) are not `$utilities` entries, so the key cannot reach them —
|
|
314
|
+
change the component's own breakpoint class instead, and never write a responsive helper name the
|
|
315
|
+
map cannot produce. Read the generated selector out of the compiled output before using it.
|
|
316
|
+
|
|
305
317
|
### Layout and type extensions
|
|
306
318
|
|
|
307
319
|
These are **project-generated classes**, not stock Bootstrap utilities. Use the existing project
|
|
308
|
-
roles when present. Otherwise add only the needed entries; the values
|
|
320
|
+
roles when present. Otherwise add only the needed entries; the values in the following block are illustrative role
|
|
309
321
|
definitions, not universal sizes.
|
|
310
322
|
|
|
311
323
|
Scale steps go in the map-override slot (after `variables-dark`, before `maps`). Keys `0`–`5`
|
|
@@ -393,7 +405,7 @@ Use `w-100 measure-form` for a bounded form, `measure-prose` for a reading colum
|
|
|
393
405
|
sibling, `max-block-lg-table` only for a warranted wide-screen bounded table scroller, `figures-tabular` for comparable
|
|
394
406
|
quantities, `ls-tight` on `display-*` and `fs-1`, and `ls-wide` with `text-uppercase` labels (`em`
|
|
395
407
|
is correct for tracking: it follows the element's own size). Verify those selectors in the
|
|
396
|
-
compiled output before using
|
|
408
|
+
compiled output before using those classes. The font must support tabular figures. A `ch`
|
|
397
409
|
measure is a starting width, not a character-count proof.
|
|
398
410
|
|
|
399
411
|
Without a Sass build, take an existing equivalent; otherwise propose the smallest stylesheet rule
|
|
@@ -432,7 +444,8 @@ under [SKILL.md](../SKILL.md) → When custom CSS is justified. Never ship an un
|
|
|
432
444
|
|
|
433
445
|
- Validate a field **on blur** — after the user leaves it — never on every keystroke, and never before the user has reached the field. Exception: live feedback that _helps_ while typing (password strength, username availability, character counts).
|
|
434
446
|
- After a field enters an error state, re-validate as the user types so they see the fix land.
|
|
435
|
-
- Always re-check everything on submit. Keep the submit button **enabled** — a disabled submit hides _what is_ wrong; a validating submit shows it.
|
|
447
|
+
- Always re-check everything on submit. Keep the submit button **enabled** while fields are invalid — a disabled submit hides _what is_ wrong; a validating submit shows it.
|
|
448
|
+
- **Separate invalid from pending.** While a submit is in flight, mark the button busy — `aria-busy="true"`, a `spinner-border spinner-border-sm` inside it, its label held so the geometry does not move — and refuse a second submit from the handler. Blocking a duplicate submit of a form that already validated is a pending state; the preceding rule bars only the disable that stands in for validation. Clear the busy state on both the resolved and the failed path, and put the failure in the error summary.
|
|
436
449
|
- On failed submit of a long form, render an **error summary** at the top (focus it; link each item to its field) _and_ inline messages at each field — never summary-only, never inline-only.
|
|
437
450
|
- Error style = color + icon + text, stating what is wrong and how to fix it. Wire message to field with `aria-describedby`, mark the field `aria-invalid="true"`. Never report errors through a hover tooltip.
|
|
438
451
|
|
|
@@ -522,7 +535,7 @@ el.addEventListener('hidden.bs.modal', () => {
|
|
|
522
535
|
})
|
|
523
536
|
```
|
|
524
537
|
|
|
525
|
-
- **
|
|
538
|
+
- **In a virtual-DOM app, take the framework-native implementation** — React Bootstrap, BootstrapVueNext, ng-bootstrap — which reuses Bootstrap's CSS and owns the DOM. Use raw `bootstrap.*` JS there only for a leaf widget the component fully controls, and dispose it on unmount. Bootstrap's JS and the framework mutating the same nodes produces stuck dropdowns and ghost backdrops.
|
|
526
539
|
|
|
527
540
|
### Popper
|
|
528
541
|
|
|
@@ -541,26 +554,26 @@ Hold the baseline in [SKILL.md](../SKILL.md) → Accessibility baseline. Its Boo
|
|
|
541
554
|
|
|
542
555
|
**Measuring the bars:**
|
|
543
556
|
|
|
544
|
-
- Hold the bars from [SKILL.md](../SKILL.md) → Surfaces, color, contrast
|
|
557
|
+
- Hold the bars from [SKILL.md](../SKILL.md) → Surfaces, color, contrast, which owns them. WCAG 2.2 permits 3:1 for large text; this skill does not — size grants no lower tier.
|
|
545
558
|
- Measure each declared theme from the compiled cascade, never from token names. A light-theme result does not establish a dark-theme result, and a skin's values are its own.
|
|
546
559
|
- Focus rings and hover fills are UI graphics: they are in scope for the 3:1 bar.
|
|
547
560
|
- Disabled controls are exempt from the bars by the spec. That exemption covers legibility, not meaning — see [Destructive actions](#destructive-actions) for the one disabled state that still has to change color.
|
|
548
561
|
|
|
549
|
-
**The instrument.** Bootstrap paints in translucent layers
|
|
562
|
+
**The instrument.** Refuse a reading from a reader that stops at the first painted ancestor and drops its alpha. Bootstrap paints in translucent layers — a card header and footer are a 3% tint of the body color over the card's own background — so a flattening reader passes an unreadable pairing and fails a readable one. Use a reader that:
|
|
550
563
|
|
|
551
564
|
- collects every painted layer from the element upward to the first opaque one, then composites them top over bottom (Porter-Duff `over`) onto that opaque base;
|
|
552
565
|
- composites a translucent foreground over that result before taking the ratio, rather than reading the declared color;
|
|
553
|
-
- measures each declared theme in the same run,
|
|
566
|
+
- measures each declared theme in the same run, because a theme swap re-points the tokens under every layer;
|
|
554
567
|
- carries a negative control drawn from outside the population it covers — a pairing known to fail — and voids the run if that negative control passes.
|
|
555
568
|
|
|
556
569
|
Include ancestor opacity in the painted stack. For images, gradients, masks, or blend modes the
|
|
557
570
|
reader does not support, use a suitable rendered-background measurement or leave the pairing open;
|
|
558
571
|
never flatten a variable background to its average color. Name reached states beside every result.
|
|
559
|
-
Wire the reader into the suite
|
|
572
|
+
Wire the reader into the suite after it has settled a question.
|
|
560
573
|
|
|
561
|
-
### WCAG 2.2
|
|
574
|
+
### WCAG 2.2 requirements for app UI
|
|
562
575
|
|
|
563
|
-
- **Target size
|
|
576
|
+
- **Target size (2.5.8, AA) — this section owns the skill's target dimensions.** Hold every applicable target at ≥ 24×24 CSS px: icon buttons, row actions, close buttons, sort carets, checkbox hit-areas, and color swatches. A smaller visual target passes only where a 24px spacing circle around it stays undisturbed — so in tight `table-sm` toolbars, pad the hit area rather than enlarging the glyph. Prefer 44×44 CSS px for a primary mobile control. Measure the rendered hit area; never infer it from a size class such as `btn-sm`. Enlarge the button or its associated label, not the icon's surrounding decoration.
|
|
564
577
|
- **Focus not obscured (2.4.11, AA).** Sticky headers/footers/action bars and toast overlays must not bury the focused element. Reserve space with `scroll-margin-top` on focusables (or `scroll-padding-top` on the scroll container) equal to the sticky chrome height.
|
|
565
578
|
- **Dragging alternatives (2.5.7, AA).** Any drag (row reorder, kanban, slider, resize) needs a non-drag single-pointer path: move up/down buttons, numeric input, click-to-place.
|
|
566
579
|
- **Accessible authentication (3.3.8, AA).** Never block paste in password/OTP fields; support password managers; no puzzle as the only way in.
|
|
@@ -585,7 +598,7 @@ Browsers handle focus on full page loads; in an SPA **you** do:
|
|
|
585
598
|
- On route change, move focus to the new view's `h1` (or the `<main>` with `tabindex="-1"`) so SR users hear where they landed.
|
|
586
599
|
- On failed submit, focus the error summary. On a compact destructive confirm, focus the safe action; in a scrolling or structured dialog, focus a static heading at the start when an action would scroll its context away.
|
|
587
600
|
- After deleting a row, move focus to a sensible neighbor (next row / the table region), never let it fall to `<body>`.
|
|
588
|
-
- Anything focused programmatically under sticky chrome needs the `scroll-margin-top` offset (2.4.11
|
|
601
|
+
- Anything focused programmatically under sticky chrome needs the `scroll-margin-top` offset (Focus not obscured, 2.4.11, under [WCAG 2.2 requirements for app UI](#wcag-22-requirements-for-app-ui)).
|
|
589
602
|
|
|
590
603
|
### Reduced motion
|
|
591
604
|
|
|
@@ -667,7 +680,7 @@ The Bootstrap implementation — a responsive offcanvas that renders inline abov
|
|
|
667
680
|
|
|
668
681
|
### Dense data tables
|
|
669
682
|
|
|
670
|
-
**Semantics first — table vs grid.** Default to a static `<table>`: links and buttons inside cells ride the natural tab order and screen readers get real table navigation free. Reserve `role="grid"` for _editable, cell-interactive_ spreadsheet-like UIs — grid
|
|
683
|
+
**Semantics first — table vs grid.** Default to a static `<table>`: links and buttons inside cells ride the natural tab order and screen readers get real table navigation free. Reserve `role="grid"` for _editable, cell-interactive_ spreadsheet-like UIs — a grid hands roving tabindex and full arrow-key cell navigation to the implementation. Never bolt `role="grid"` onto a read-only table because it "looks like a data grid": semantics follow interaction, not appearance.
|
|
671
684
|
|
|
672
685
|
**Craft rules:**
|
|
673
686
|
|
|
@@ -678,7 +691,7 @@ The Bootstrap implementation — a responsive offcanvas that renders inline abov
|
|
|
678
691
|
independent column comparison or sorting. Keep key comparison columns explicit. Quiet repeated
|
|
679
692
|
labels and row actions before increasing density.
|
|
680
693
|
- **Density:** `table-sm` for compact; offer density as a user toggle (comfortable/compact) driven by one token or wrapper class, not per-cell tweaks. Do not shrink font below readability to fake density.
|
|
681
|
-
- **Sticky header** when the table
|
|
694
|
+
- **Sticky header** when the table scrolls its own header out of view. Not built into Bootstrap — the pattern:
|
|
682
695
|
|
|
683
696
|
```html
|
|
684
697
|
<div
|
|
@@ -710,7 +723,7 @@ Keep sticky header cells on an **opaque, mode-aware surface** such as `bg-body-s
|
|
|
710
723
|
</th>
|
|
711
724
|
```
|
|
712
725
|
|
|
713
|
-
- **Row actions:**
|
|
726
|
+
- **Row actions:** keep the high-frequency actions inline and put the rest behind a per-row kebab (dropdown). Hover-only reveal fails touch and keyboard — keep at least the overflow trigger always visible and at the floor in [WCAG 2.2 requirements for app UI](#wcag-22-requirements-for-app-ui).
|
|
714
727
|
- **Selection & bulk actions:** header checkbox with indeterminate state for partial selection; per-row checkboxes with `aria-label` naming the row ("Select INV-1042"). When selection > 0, swap the toolbar's content in place for a contextual bar — "3 selected", the batch actions, and a clear-selection escape — never push the layout down (layout-shifting chrome is an anti-pattern). Announce the count through a polite live region.
|
|
715
728
|
- **Pagination vs scrolling:** paginate when users need position, totals, deep links, and "go to page N" — most enterprise CRUD. Virtualize (windowed rendering) for long uniform lists where scrolling is natural. True infinite scroll is for exploratory feeds only — never where users need a footer or a findable end.
|
|
716
729
|
- **Responsive, by task:** use a compact record list for record work, a locally scrollable semantic table for essential comparison, or priority columns with an operable detail path. Preserve identity, decision fields, and actions. Choose expansion from available container width, not `md` by habit. Keep one state model across variants; take the contract from [Keep the task intact](responsive-layout.md#keep-the-task-intact).
|
|
@@ -718,7 +731,7 @@ Keep sticky header cells on an **opaque, mode-aware surface** such as `bg-body-s
|
|
|
718
731
|
|
|
719
732
|
### Filter & search bars
|
|
720
733
|
|
|
721
|
-
- One toolbar above the table: search input first (`role="search"` on the form), then the
|
|
734
|
+
- One toolbar above the table: search input first (`role="search"` on the form), then the highest-value filters as `form-select`/segmented controls, overflow filters behind a "Filters" button (offcanvas on mobile, dropdown/collapse on desktop). Promote a filter to the toolbar because the task reaches for it, not to fill the row.
|
|
722
735
|
- **Active filters must be visible and dismissible** — chips/badges with an ✕ and a "Clear all" — users must see _why_ the list is short. A filtered-empty state repeats the escape hatch.
|
|
723
736
|
- Debounce live search; show result counts ("128 results") so feedback is immediate; filter state belongs in the URL when views are shareable.
|
|
724
737
|
- At the base, give search a full row; stack or wrap actions and filters without shrinking labels or targets. Expand with `col-12 col-md`, `col-md-auto`, or `d-grid d-sm-flex` when they fit. Reserve a horizontal scroller for a documented spatial interaction, not an ordinary toolbar. Keep active filters and the clear path outside any disclosed extras.
|
|
@@ -729,7 +742,7 @@ Keep sticky header cells on an **opaque, mode-aware surface** such as `bg-body-s
|
|
|
729
742
|
⟨total⟩", where the wizard fills in its own runtime position and total); `list-group-numbered` or
|
|
730
743
|
a simple nav renders it honestly.
|
|
731
744
|
- Validate per step before advancing; never let a step advance carrying invalid data.
|
|
732
|
-
- Back never loses data. Persist partial state (save-and-resume) for
|
|
745
|
+
- Back never loses data. Persist partial state (save-and-resume) for a long sequence or one that crosses sessions.
|
|
733
746
|
- Never re-ask what a previous step collected (Redundant Entry, 3.3.7) — carry it forward or offer "same as above".
|
|
734
747
|
- Review step: a review summary with per-section edit links, then one clearly-named commit action ("Create account", not "Submit").
|
|
735
748
|
|
|
@@ -764,7 +777,7 @@ Blocking errors are never toasts. Keep the acting verb consistent across the flo
|
|
|
764
777
|
|
|
765
778
|
Match friction to reversibility × blast radius:
|
|
766
779
|
|
|
767
|
-
1. **Undo** (soft-delete + toast with Undo) for reversible, low-stakes, frequent actions
|
|
780
|
+
1. **Undo** (soft-delete + toast with Undo) for reversible, low-stakes, frequent actions. Prefer making actions undoable over interrupting them.
|
|
768
781
|
2. **Confirm dialog** for irreversible-but-scoped operations. Restate the specific consequence ("This permanently deletes 3 invoices"), verb-labeled buttons ("Delete invoices" / "Cancel" — never Yes/No), destructive action visually separated from safe; `alertdialog` semantics; focus lands on the safe action for a compact confirmation, or a static top heading when focusing an action would scroll the consequences out of view.
|
|
769
782
|
3. **Type-to-confirm** (type the entity name) only for high-blast-radius irreversible operations — delete an org, drop a dataset.
|
|
770
783
|
|
|
@@ -791,7 +804,7 @@ Do not type-gate a single-row delete; do not one-tap a tenant wipe. Confirm only
|
|
|
791
804
|
## Performance
|
|
792
805
|
|
|
793
806
|
- **Keep one CSS system.** Extend the installed Bootstrap theme; do not add a competing framework or a parallel palette to restyle the surface.
|
|
794
|
-
- **
|
|
807
|
+
- **Ship the full compressed build, or trim it with a Sass-subset build** that imports only the parts used (see [Theming](#theming--design-tokens)). Do not reach for a CSS purge tool first. Bootstrap adds classes **at runtime** — `show`, `showing`, `fade`, `collapsing`, `modal-open`, `modal-backdrop`, `offcanvas-backdrop`, and tooltip/popover generated markup — so a purge without a safelist ships a UI whose modals stop rendering. Where the project purges anyway, safelist every JS-toggled class and drive every overlay before shipping.
|
|
795
808
|
- **Icons:** Bootstrap Icons is a separate package — prefer inline SVG or an SVG sprite (crisp, styleable through `currentColor`, no font flash) over the icon font; load only the icons used.
|
|
796
809
|
- **JS:** the bundle is small, but only load it where behavior exists; per-component ESM imports (`bootstrap/js/dist/modal`) trim further in bundlers.
|
|
797
810
|
- **Fonts:** reuse the existing families and load only needed weights/scripts. Add a display face only for a distinct role; use `font-display: swap` and test fallback wrapping. Keep the data face legible before and after fonts load.
|
|
@@ -800,9 +813,9 @@ Do not type-gate a single-row delete; do not one-tap a tenant wipe. Confirm only
|
|
|
800
813
|
|
|
801
814
|
Bootstrap has **no** combobox/autocomplete, date picker, multi-select tags input, data grid, or tree view. The boundary rule:
|
|
802
815
|
|
|
803
|
-
- **
|
|
804
|
-
- **
|
|
805
|
-
- **
|
|
816
|
+
- **Use native controls:** `<input type="date">`, `<datalist>` for light autocomplete, and `<select multiple>` where suitable.
|
|
817
|
+
- **Use an established accessible library** when native controls cannot meet the product's widget requirements; audit it against the APG contract.
|
|
818
|
+
- **Implement a custom widget** only when native controls and an established accessible library cannot satisfy the requirements; read [Accessibility](#accessibility) → Pattern contracts and cover the required keyboard behavior.
|
|
806
819
|
- Never fake it: a `.dropdown-menu` posing as a select, a `<div>` grid with click handlers, or a scroll-anchor "wizard" each break keyboard and AT users in ways a demo never shows.
|
|
807
820
|
|
|
808
821
|
## Common Layout Patterns
|
|
@@ -839,3 +852,20 @@ Bootstrap has **no** combobox/autocomplete, date picker, multi-select tags input
|
|
|
839
852
|
<div class="d-none d-md-block">Hidden on mobile, visible md+</div>
|
|
840
853
|
<div class="d-md-none">Visible only below md</div>
|
|
841
854
|
```
|
|
855
|
+
|
|
856
|
+
`d-none` removes the element from layout and the accessibility tree, which is what makes a dual presentation legal: only the active view exposes its controls. It is not a content strategy — anything hidden at the base must remain reachable through an operable path ([responsive-layout.md](responsive-layout.md) → Keep the task intact). A generated responsive role, for a utility-map property with no shipped infix:
|
|
857
|
+
|
|
858
|
+
```scss
|
|
859
|
+
$utilities: map-merge(
|
|
860
|
+
$utilities,
|
|
861
|
+
(
|
|
862
|
+
'width': map-merge(
|
|
863
|
+
map-get($utilities, 'width'),
|
|
864
|
+
(
|
|
865
|
+
responsive: true,
|
|
866
|
+
)
|
|
867
|
+
),
|
|
868
|
+
)
|
|
869
|
+
);
|
|
870
|
+
// generates w-md-auto, w-lg-50, … alongside the stock w-*
|
|
871
|
+
```
|