@codenhub/styles 0.5.0 → 0.7.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.
Files changed (119) hide show
  1. package/NOTICE +18 -16
  2. package/README.es.md +61 -0
  3. package/README.md +27 -22
  4. package/README.pt-BR.md +61 -0
  5. package/dist/aesthetics/chunky-tile.css +1 -1
  6. package/dist/aesthetics/cyber.css +1 -1
  7. package/dist/aesthetics/glass.css +1 -1
  8. package/dist/aesthetics/index.css +2 -2
  9. package/dist/aesthetics/neobrutalism.css +1 -1
  10. package/dist/aesthetics/pixel.css +1 -1
  11. package/dist/aesthetics/sketch.css +1 -1
  12. package/dist/components.css +2 -2
  13. package/dist/index.css +2 -2
  14. package/dist/native.css +2 -2
  15. package/dist/palette.css +1 -1
  16. package/dist/theme.css +2 -2
  17. package/dist/tw/aesthetics/chunky-tile.css +120 -62
  18. package/dist/tw/aesthetics/cyber.css +102 -40
  19. package/dist/tw/aesthetics/glass.css +371 -19
  20. package/dist/tw/aesthetics/index.css +2 -1
  21. package/dist/tw/aesthetics/neobrutalism.css +121 -33
  22. package/dist/tw/aesthetics/pixel.css +111 -16
  23. package/dist/tw/aesthetics/sketch.css +100 -28
  24. package/dist/tw/box.css +69 -28
  25. package/dist/tw/components/button.css +35 -14
  26. package/dist/tw/components/feedback.css +61 -58
  27. package/dist/tw/components/form.css +255 -142
  28. package/dist/tw/components/index.css +4 -9
  29. package/dist/tw/components/surface.css +80 -68
  30. package/dist/tw/components/tooltip.css +75 -41
  31. package/dist/tw/elevation.css +14 -22
  32. package/dist/tw/index.css +15 -19
  33. package/dist/tw/intent.css +35 -27
  34. package/dist/tw/native.css +22 -12
  35. package/dist/tw/palette.css +14 -11
  36. package/dist/tw/presentation.css +16 -30
  37. package/dist/tw/reset.css +36 -43
  38. package/dist/tw/surface.css +11 -12
  39. package/dist/tw/theme.css +87 -103
  40. package/dist/tw/utilities/content.css +311 -200
  41. package/dist/tw/utilities/layout.css +41 -37
  42. package/docs/accessibility.md +104 -58
  43. package/docs/changelog/0.1.1.md +1 -0
  44. package/docs/changelog/0.2.0.md +1 -0
  45. package/docs/changelog/0.3.0.md +1 -0
  46. package/docs/changelog/0.4.0.md +1 -0
  47. package/docs/changelog/0.5.0.md +8 -3
  48. package/docs/changelog/0.6.0.md +53 -0
  49. package/docs/changelog/0.7.0.md +50 -0
  50. package/docs/changelog/index.md +2 -0
  51. package/docs/concepts.md +188 -46
  52. package/docs/es/accessibility.md +150 -0
  53. package/docs/es/concepts.md +212 -0
  54. package/docs/es/index.md +104 -0
  55. package/docs/es/integrating/astro.md +35 -0
  56. package/docs/es/integrating/index.md +47 -0
  57. package/docs/es/integrating/nextjs.md +67 -0
  58. package/docs/es/integrating/svelte.md +45 -0
  59. package/docs/es/integrating/tailwind.md +78 -0
  60. package/docs/es/integrating/vue.md +31 -0
  61. package/docs/es/integrating/without-a-bundler.md +115 -0
  62. package/docs/es/setup.md +180 -0
  63. package/docs/es/usage/aesthetics.md +276 -0
  64. package/docs/es/usage/buttons.md +131 -0
  65. package/docs/es/usage/composing.md +164 -0
  66. package/docs/es/usage/content-and-layout.md +215 -0
  67. package/docs/es/usage/customizing.md +298 -0
  68. package/docs/es/usage/feedback.md +153 -0
  69. package/docs/es/usage/forms.md +231 -0
  70. package/docs/es/usage/index.md +29 -0
  71. package/docs/es/usage/solo.md +84 -0
  72. package/docs/es/usage/theming.md +296 -0
  73. package/docs/es/usage/tooltips.md +127 -0
  74. package/docs/index.md +89 -21
  75. package/docs/integrating/astro.md +3 -4
  76. package/docs/integrating/index.md +18 -13
  77. package/docs/integrating/nextjs.md +4 -5
  78. package/docs/integrating/svelte.md +5 -4
  79. package/docs/integrating/tailwind.md +29 -8
  80. package/docs/integrating/vue.md +3 -4
  81. package/docs/integrating/without-a-bundler.md +114 -0
  82. package/docs/pt-BR/accessibility.md +150 -0
  83. package/docs/pt-BR/concepts.md +212 -0
  84. package/docs/pt-BR/index.md +104 -0
  85. package/docs/pt-BR/integrating/astro.md +35 -0
  86. package/docs/pt-BR/integrating/index.md +47 -0
  87. package/docs/pt-BR/integrating/nextjs.md +67 -0
  88. package/docs/pt-BR/integrating/svelte.md +45 -0
  89. package/docs/pt-BR/integrating/tailwind.md +78 -0
  90. package/docs/pt-BR/integrating/vue.md +31 -0
  91. package/docs/pt-BR/integrating/without-a-bundler.md +115 -0
  92. package/docs/pt-BR/setup.md +180 -0
  93. package/docs/pt-BR/usage/aesthetics.md +276 -0
  94. package/docs/pt-BR/usage/buttons.md +131 -0
  95. package/docs/pt-BR/usage/composing.md +164 -0
  96. package/docs/pt-BR/usage/content-and-layout.md +215 -0
  97. package/docs/pt-BR/usage/customizing.md +298 -0
  98. package/docs/pt-BR/usage/feedback.md +153 -0
  99. package/docs/pt-BR/usage/forms.md +231 -0
  100. package/docs/pt-BR/usage/index.md +29 -0
  101. package/docs/pt-BR/usage/solo.md +84 -0
  102. package/docs/pt-BR/usage/theming.md +296 -0
  103. package/docs/pt-BR/usage/tooltips.md +127 -0
  104. package/docs/setup.md +134 -91
  105. package/docs/usage/aesthetics.md +102 -65
  106. package/docs/usage/buttons.md +108 -40
  107. package/docs/usage/composing.md +105 -92
  108. package/docs/usage/content-and-layout.md +159 -127
  109. package/docs/usage/customizing.md +112 -43
  110. package/docs/usage/feedback.md +135 -70
  111. package/docs/usage/forms.md +184 -99
  112. package/docs/usage/index.md +18 -14
  113. package/docs/usage/solo.md +83 -0
  114. package/docs/usage/theming.md +260 -119
  115. package/docs/usage/tooltips.md +103 -42
  116. package/llms-full.txt +2465 -1272
  117. package/llms.txt +25 -17
  118. package/package.json +28 -35
  119. package/dist/tw/components/loader.css +0 -117
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: 0.7.0
3
+ date: 2026-11-04
4
+ description: Liquid glass buttons, solo classes that compose with presentation, intent, and elevation, the shipped loaders removed in favor of icon spinners, and fixes to layout gaps, dialog margins, tables, switches, field groups, and forced colors.
5
+ ---
6
+
7
+ # 0.7.0
8
+
9
+ A button can be a liquid glass pane, the solo classes compose with presentation, intent, and elevation the way components do, the loaders are gone in favor of a spinner from an icon set, and a round of fixes to nested layout gaps, dialog placement, table rows, right-to-left switches, field groups, and forced colors.
10
+
11
+ ## Added
12
+
13
+ - **Liquid glass buttons.** A `.btn` carrying `.glass-liquid` itself, in a glass scope, takes the blur, lens, and rim of a liquid pane, with a lens sized for a control. The fill is still the presentation's: `.solid` is an opaque plate under the rim, `.ghost` and `.soft` are clear panes. A liquid region alone still leaves its controls solid. See [Aesthetics → Liquid buttons](../usage/aesthetics.md#liquid-buttons).
14
+ - **Solo classes compose with presentation, intent, and elevation.** Fill and edge come from the element or a container, intent and elevation from the element's own class, so `.pixel-solo.edgeless` drops its ring, `.glass-solo.solid.success` is an opaque green pane, and `.neobrutalism-solo.flat` has no slab. With none of those classes a solo element paints what it did. See [Aesthetics → Solo classes](../usage/aesthetics.md#solo-classes).
15
+ - **`--font-mono` is a documented token.** It sets the font of the `kbd`, `code`, and `pre` helpers and of `<kbd>`, `<code>`, and `<pre>` under `/native`, and joins the other font tokens in [Theming → Fonts](../usage/theming.md#fonts), which also shows how to load a web font.
16
+ - **Linking without a bundler.** [Integrating → Without a bundler](../integrating/without-a-bundler.md) covers plain HTML, Rails, Django, and a CDN `<link>`, which load the compiled files by path rather than by package name.
17
+ - **A stated versioning policy.** Below 1.0 a minor release may break and a patch release never does; see [Versioning](../index.md#versioning).
18
+
19
+ ## Changed
20
+
21
+ - **A solo element inside a `.solid`, `.soft`, or `.ghost` container takes that fill and the theme's text color**, since presentation cascades to it now as it does to components. A solo element whose own background does not follow the theme -- a dark toast on a light page -- inside such a container prints the theme's text; keep it out of the container, or give it `.solid` with an intent.
22
+ - **`.tight` and `.loose` stay on their own element.** They wrote `--layout-gap`, which inherits, so a plain `.stack`, `.view`, `.cluster`, or `.auto-grid` nested inside one took its gap. A nested layout keeps the default gap now; set `--layout-gap` on a container to change the gap of every layout inside it.
23
+ - **Your margin places a component dialog.** The centring of an open `<dialog class="card">` (or `.panel`, `.surface`) overruled your margin utilities and unlayered CSS; it now sits in `utilities` at zero specificity, so `mt-8` or your own rule wins, and it still beats a `base` reset such as Preflight's. A margin reset in a cascade layer of your own, declared after the package's, now wins over the centring too, as it already does over every component property.
24
+ - **`.cyber` glows from the outline.** Its glow is the intent color at 60% with a 1px spread, up from 40% with none, so the brightest point sits on the element's outline. An edgeless button, badge, or panel read as backlit -- a shadow on a dark page -- because the glow just outside it was brighter than its own fill. `.cyber-solo` takes the same glow. In the light theme the near-black glow of a neutral component is heavier too; a hued `--cyber-ink` is still the way to make it read as light there.
25
+ - **The neutral palette values carry no hue.** `--palette-border`, `--palette-surface`, and `--palette-text` are `oklch(… 0 none)` in both themes, where they were `oklch(… 0 0)`. The colors themselves are unchanged, but a missing hue takes its partner's in polar interpolation: `color-mix(in oklch, var(--palette-text), oklch(60% 0.2 240))` now lands on hue 240, a blue, where it travelled from hue 0 and landed on a purple. To keep the old result, give the neutral its old hue: `color-mix(in oklch, oklch(from var(--palette-text) l c 0), oklch(60% 0.2 240))`. Mixing in `oklab` does not, since a hueless neutral adds no hue there and the mix stays blue.
26
+
27
+ ## Removed
28
+
29
+ - **The loaders.** `.loader`, its `.sm` and `.lg` sizes, the nine variants (`.dots-wave`, `.dots-fade`, `.dots-queue`, `.dots-rotate`, `.dots-grow`, `.dots-grow-alternate`, `.dot-bounce`, `.bars-wave`, `.pulse-ring`), `.loader-mask`, and the `@codenhub/styles/tw/loader` entrypoint are gone. Importing `/tw/loader` now fails to resolve, and `<span class="loader dots-wave">` in the complete CSS renders nothing. `.sm` and `.lg` on other components are unchanged. Use a spinner from an icon set instead, such as `@codenhub/icons`, which this package does not import: a glyph with `ic-anim-spin` (`ic-lucide-loader-circle ic-anim-spin`) or the animated `svg-spinners` family, both in `currentColor`. Under `prefers-reduced-motion: reduce` every loader showed a still ring; a glyph with `ic-anim-spin` stops there too, but `svg-spinners` artwork keeps moving, so choose the glyph where that matters. See [Feedback](../usage/feedback.md) for loading the icons.
30
+
31
+ ## Fixed
32
+
33
+ - **A focused `.solid.primary` control under `.pixel` shows its focus.** The inset focus ring is the primary color, so it vanished into the fill; a line of the page color now sits inside it. `.pixel-solo` takes the same line.
34
+ - **Controls and surfaces under `.pixel` keep an edge in forced colors.** Pixel draws its edge as an inset shadow, which forced colors remove, so buttons, fields, and cards had no boundary; forced colors now draw a solid border and drop the clip. `.pixel-solo` draws an inward outline there.
35
+ - **A `.disabled` text field holds still under the pointer.** The class spelling of disabled still darkened an `.ipt`'s line on hover, unlike `disabled`, `aria-disabled`, and `data-disabled`.
36
+ - **`.sketch-rounded` beside `.sketch-solo` stays on the solo element.** Its radius tokens inherited into the element's contents, so a `.btn` inside a rounded sketch toast drew a sketch outline on a page with no sketch in scope.
37
+ - **A checked native radio looks like a checked `.radio` in forced colors.** Under `/native` it drew a Highlight ring and dot on Canvas, where `.radio` draws a Highlight disc with a HighlightText dot, so `<input type="radio" class="radio">` changed look with the entrypoint. Both draw the disc now.
38
+ - **`/theme` declares every documented color and foundation token**, except `--focus-ring-offset`, which is computed on the focused element, and the `/tw`-only `--breakpoint-xs`. The compiled entry left out `--color-background`, `--color-foreground`, `--color-text-secondary`, and `--font-default`, because nothing in it read them, so `var(--color-background)` in your own CSS over `/theme` alone resolved to nothing.
39
+ - **A liquid region blurs what takes no liquid layers.** A bare `<table>` under `/native` or your own `@apply surface` inside a `.glass-liquid` region took its clearer ground with nothing blurred behind it; it takes liquid's lighter blur now.
40
+ - **Liquid's corners stay off a solo element's contents.** `.glass-solo.glass-liquid` no longer hands liquid's corner tokens to what it holds, so a `.btn` inside a liquid solo toast keeps the page's corners.
41
+ - **A checked `.switch` stays in its track right to left.** Under `dir="rtl"` the checked knob moved the left-to-right way, out past the track's right edge; it sits at the inline end, the left, now.
42
+ - **A table row shows its own intent.** A `<tr class="destructive">` in a `.data-table.success` kept the table's green text, rule, and hover, because the table resolved them before the row's intent applied. A row with an intent draws them in its own now; on a `.solid` table its text keeps the table's ink -- the contrast ink on a hued table, the table's own text color on a neutral one -- which that plate needs. Other rows keep the table's.
43
+ - **A button in an `.input-group` keeps its own edge.** The field's line reached every component inside the group, so a `.ghost` or `.edgeless` clear button drew a border the field's color. It rests as it does outside the group now, and the group keeps its line.
44
+ - **An `.alert` in another aesthetic nested under `.neobrutalism` casts no slab.** Neobrutalism raised the elevation of every alert below it, so one inside a `.chunky-tile`, `.glass`, `.pixel`, `.cyber`, or `.sketch` region took neobrutalism's shadow, unlike a card there. It takes the nested aesthetic's look now, and a `.neobrutalism` region nested inside that one still rests its alerts on the slab.
45
+ - **A select keeps its drop-down arrow in forced colors.** The chevron is drawn with gradients, which forced colors remove, so in Chromium and Firefox a `.select` or a native `<select>` under `/native` read as a text field. A single-row select shows the platform's arrow there now.
46
+ - **An `.input-group` holding a disabled control holds still under the pointer.** The group dimmed and showed the not-allowed cursor, but its line still darkened on hover; it no longer does.
47
+ - **A padding modifier pads only its own card or panel.** `.p-xs`, `.p-sm`, `.p-lg`, and `.flush` on a `.card` or `.panel` reached every card and panel nested inside it, so a card in a `.card.p-xs` sat at 8px instead of its 20px, and one in a `.flush` card had none. A nested surface keeps its own padding now; give it a modifier of its own to change it.
48
+ - **A long select label in an `.input-group` stops short of the chevron.** The group took the select's inline padding, so a label too long for the field ran under the drop-down arrow, at the right or, right to left, at the left. A single-row select keeps room for its chevron at the inline end now.
49
+ - **Typed text in a hued or invalid field reads at 4.5:1.** The text in `.ipt`, `.textarea`, and `.select` was the intent's base color, which fell as low as 2.5:1 against the field: a `.warning` field in the light theme, and `.success`, `.destructive`, `.info`, and `aria-invalid="true"` fields in the dark one, worst on `.soft` and `.solid`. It is the intent's strong tone now, darker in light and lighter in dark, at 4.5:1 or better for every intent and presentation in both themes. The field's line, focus ring, and fill are unchanged. Native fields under `/native` take the same text. A field with no intent class takes the neutral strong tone too, so its text is a shade different from 0.6.
50
+ - **The package's NOTICE covers the checkbox marks' Feather origin.** The checkbox check and indeterminate minus come from Lucide icons derived from Feather, and NOTICE now carries Feather's MIT notice beside Lucide's ISC one.
@@ -6,6 +6,8 @@ group: Changelog
6
6
 
7
7
  # Changelog
8
8
 
9
+ - [0.7.0](0.7.0.md)
10
+ - [0.6.0](0.6.0.md)
9
11
  - [0.5.0](0.5.0.md)
10
12
  - [0.4.0](0.4.0.md)
11
13
  - [0.3.0](0.3.0.md)
package/docs/concepts.md CHANGED
@@ -1,69 +1,211 @@
1
1
  ---
2
- title: Concepts
3
- description: The three-axis model, the token system, and how theme selection works.
4
- order: 2
2
+ title: Building a screen
3
+ description: Lay out the settings page, set its type, and add cards and buttons while learning intent, fill, edge, and aesthetic.
4
+ order: 3
5
5
  ---
6
6
 
7
- # Concepts
7
+ # Building a screen
8
8
 
9
- Read this before the usage guides. It explains the mental model every component, token, and class in this package shares.
9
+ This page turns the empty shell from [Setup](./setup.md) into the first real part of the settings screen: a page header, a profile card with Save and Cancel buttons, and a plan summary beside a usage card. On the way it introduces the three choices every component makes, intent, presentation, and aesthetic, at the moment the screen needs each one. Everything else in these docs builds on this model.
10
10
 
11
- ## The three axes
11
+ ## The smallest screen
12
12
 
13
- Every component separates three independent choices, so each can change without a component-specific variant:
13
+ A page header and one card with one button:
14
14
 
15
- | Axis | Question | Classes | Inheritance |
16
- | ------------ | --------------- | --------------------------------------------------------------------------------------------------- | ------------ |
17
- | Intent | Which color? | `.primary`, `.secondary`, `.success`, `.warning`, `.destructive`, `.info` | Element only |
18
- | Presentation | How much of it? | `.solid`, `.soft`, `.ghost`, `.edged`, `.edgeless` | Cascades |
19
- | Aesthetic | Made of what? | `.neobrutalism`, `.glass`, `.pixel`, `.chunky-tile`, `.cyber` from an optional aesthetic stylesheet | Cascades |
15
+ ```html
16
+ <main class="section">
17
+ <div class="section-content narrow stack">
18
+ <h1 class="text-title">Account settings</h1>
19
+ <section class="card stack">
20
+ <h2 class="text-title-sm">Profile</h2>
21
+ <p>Your name appears on invoices and shared projects.</p>
22
+ <button class="btn primary" type="button">Save changes</button>
23
+ </section>
24
+ </div>
25
+ </main>
26
+ ```
27
+
28
+ Each class does one job:
29
+
30
+ - `.section` pads the page: a responsive gutter at the sides (1 to 2rem) and generous space above and below (4 to 7rem).
31
+ - `.section-content` centers a column with a maximum width; `.narrow` makes that 48rem instead of 80rem, a comfortable width for a form.
32
+ - `.stack` lays its children out vertically with a 1rem gap.
33
+ - `.text-title` and `.text-title-sm` set heading sizes: 1.875rem bold and 1.25rem semibold.
34
+ - `.card` is a bordered container with rounded corners and 1.25rem of padding.
35
+ - `.btn` makes a button, and `.primary` gives it the primary color.
36
+
37
+ Headings are not sized by their tag: the reset gives an `<h1>` with no type class the same size and weight as the text around it. That keeps the document structure, which heading level an element is, separate from the size you want it to look. If you want headings styled automatically, see [Setup → Classless HTML](./setup.md#classless-html).
38
+
39
+ ## Lay out the page
40
+
41
+ Three layout helpers cover most screens, and all three use the same gap, `--layout-gap` (1rem):
42
+
43
+ - `.stack` for vertical lists of blocks.
44
+ - `.cluster` for a row that wraps when it runs out of room, such as a group of buttons. Add `.between` to push the first and last items to opposite ends.
45
+ - `.auto-grid` for a grid of equal cards that adds or drops columns as the space changes. A column is never narrower than `--layout-grid-min` (16rem) unless the container itself is.
46
+
47
+ `.tight` (0.5rem) and `.loose` (1.5rem) change the gap of the layout they sit on. A layout nested inside keeps its own gap.
48
+
49
+ Add a header and put the buttons in a row:
20
50
 
21
51
  ```html
22
- <section class="soft pixel">
23
- <button class="btn primary">Soft primary pixel button</button>
24
- <button class="btn destructive ghost edged">Outlined destructive override</button>
25
- </section>
52
+ <main class="section">
53
+ <div class="section-content narrow stack loose">
54
+ <header class="stack tight">
55
+ <h1 class="text-title">Account settings</h1>
56
+ <p>Manage your profile, plan, and security.</p>
57
+ </header>
58
+
59
+ <section class="card stack" aria-labelledby="profile-title">
60
+ <h2 class="text-title-sm" id="profile-title">Profile</h2>
61
+ <p>Your name appears on invoices and shared projects.</p>
62
+ <div class="cluster">
63
+ <button class="btn primary" type="button">Save changes</button>
64
+ <button class="btn ghost" type="button">Cancel</button>
65
+ </div>
66
+ </section>
67
+ </div>
68
+ </main>
26
69
  ```
27
70
 
28
- Intent stays on the component so a semantic container cannot accidentally recolor nested controls. Presentation and aesthetic cascade from a container; putting either class directly on a component overrides the inherited choice. Components apply documented clamps when an axis would remove an essential edge or overwhelm compact geometry.
71
+ [Content and layout](./usage/content-and-layout.md) lists every layout helper, including `.view`, `.divider`, and `.visually-hidden`, and the full type scale.
72
+
73
+ ## Intent: which color
74
+
75
+ The Save button is `.primary` and the Cancel button has no intent, which makes it neutral. An intent class picks a color role:
76
+
77
+ | Class | Use it for | Default color |
78
+ | -------------- | ------------------------------------- | --------------------------------------- |
79
+ | _none_ | Anything without a meaning of its own | The page's text and border grays |
80
+ | `.primary` | The main action on a screen | Near-black on light, near-white on dark |
81
+ | `.secondary` | A second, quieter action | Mid gray |
82
+ | `.success` | Confirmation and completed states | Emerald green |
83
+ | `.warning` | Something that needs attention soon | Amber, with dark text |
84
+ | `.destructive` | Deleting, revoking, and errors | Rose red |
85
+ | `.info` | Neutral notices and help | Indigo |
86
+
87
+ Intent stays on the element that carries it. Putting `.destructive` on a `<section>` does not turn every button inside it red; you write it on each button. This is deliberate: a container that silently recolored everything inside it would turn a red danger zone's Cancel button red too.
88
+
89
+ `.neutral` names the default explicitly. You rarely need it, because no intent class already means neutral; it matters where color would otherwise come from elsewhere, such as a table row, which inherits its table's intent.
90
+
91
+ ## Presentation: how much color
92
+
93
+ The Cancel button is `.ghost`: no fill, just colored text, so it reads as less important than Save. That is the presentation axis, two independent choices:
94
+
95
+ - **Fill:** `.solid` fills the component with its intent color and switches the text to the contrasting color. `.soft` mixes in a light 12% tint and keeps the text in the intent color. `.ghost` has no fill at rest.
96
+ - **Edge:** `.edged` draws a border in the intent color; `.edgeless` draws none.
97
+
98
+ ```html
99
+ <button class="btn primary">Save changes</button>
100
+ <button class="btn primary soft">Preview</button>
101
+ <button class="btn primary ghost edged">Export data</button>
102
+ <button class="btn ghost">Cancel</button>
103
+ ```
104
+
105
+ Every component has its own default when no presentation class applies. A button is solid with no border. A card has no fill and a border. A form field has no fill and a border. [Composing](./usage/composing.md#component-defaults) lists the default of every component.
106
+
107
+ Unlike intent, presentation passes down. A `.soft` on a container makes everything inside it soft unless an element says otherwise, and a class on the element itself always beats one inherited from a container:
108
+
109
+ ```html
110
+ <div class="cluster soft">
111
+ <button class="btn primary">Soft primary</button>
112
+ <button class="btn success">Soft success</button>
113
+ <button class="btn primary solid">Solid: its own class wins</button>
114
+ </div>
115
+ ```
116
+
117
+ Some components limit what presentation can do, to protect something they need. A form field inherited into a `.solid` container fills to only 6%, so typed text stays readable. A checkbox always keeps its border, because the border is the only thing that shows an unchecked box. These limits are listed with each component and collected in [Composing](./usage/composing.md).
118
+
119
+ ## Finish the first screen
120
+
121
+ Add a plan summary next to a usage card in a grid, and give the summary a soft primary tint so it stands out as the account's current state:
122
+
123
+ ```html
124
+ <main class="section">
125
+ <div class="section-content narrow stack loose">
126
+ <header class="stack tight">
127
+ <h1 class="text-title">Account settings</h1>
128
+ <p>Manage your profile, plan, and security.</p>
129
+ </header>
130
+
131
+ <section class="card stack" aria-labelledby="profile-title">
132
+ <h2 class="text-title-sm" id="profile-title">Profile</h2>
133
+ <p>Your name appears on invoices and shared projects.</p>
134
+ <div class="cluster">
135
+ <button class="btn primary" type="button">Save changes</button>
136
+ <button class="btn ghost" type="button">Cancel</button>
137
+ </div>
138
+ </section>
139
+
140
+ <div class="auto-grid">
141
+ <section class="card soft primary stack tight" aria-labelledby="plan-title">
142
+ <h2 class="text-label" id="plan-title">Current plan</h2>
143
+ <p class="text-title-sm">Team, billed yearly</p>
144
+ <p class="text-body">Renews on 12 March 2027.</p>
145
+ </section>
146
+ <section class="card stack tight" aria-labelledby="usage-title">
147
+ <h2 class="text-label" id="usage-title">Storage</h2>
148
+ <p class="text-title-sm">48 GB of 100 GB</p>
149
+ <p class="text-body">Shared by 6 members.</p>
150
+ </section>
151
+ </div>
152
+ </div>
153
+ </main>
154
+ ```
155
+
156
+ On a wide window the two cards sit side by side; when the column is too narrow for two 16rem columns and the gap between them, they stack. The [Feedback](./usage/feedback.md) page turns the storage card's number into a usage bar.
157
+
158
+ A `.card` rests at one unit of depth, but on the base look that depth has no visible shadow; it appears when an aesthetic draws one or when you add `.raised` or `.floating`. [Composing → Elevation](./usage/composing.md#elevation) covers depth.
159
+
160
+ ## Aesthetic: what it is made of
161
+
162
+ The third axis changes the material of everything inside it: corners, border width, shadows, and sometimes the font. It needs its own import (see [Setup → Add an aesthetic](./setup.md#add-an-aesthetic-optional)):
163
+
164
+ ```html
165
+ <main class="section neobrutalism">
166
+ <!-- The same settings screen: square corners, thick dark lines, hard offset shadows -->
167
+ </main>
168
+ ```
29
169
 
30
- The maintained contract is the intersection of the combinations documented in [Usage](./usage/index.md) and demonstrated by the playground. Undocumented and undemonstrated combinations may produce CSS but are not supported behavior.
170
+ Like presentation, an aesthetic passes down, and a component inside it can carry a different one. You do not need it to build the screen; [Aesthetics](./usage/aesthetics.md) compares all six.
31
171
 
32
- - [Usage → Composing](./usage/composing.md) shows how the three axes combine on each component, with the full axis-support matrix.
33
- - [Usage → Aesthetics](./usage/aesthetics.md) covers each aesthetic and its documented exceptions in depth.
172
+ ## Words these docs use
34
173
 
35
- ## The token system
174
+ Some pages describe how a component is painted. These words have one meaning each:
36
175
 
37
- Tokens are CSS custom properties, grouped by what they control rather than where they're used:
176
+ | Word | Meaning |
177
+ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
178
+ | Fill | How much of the intent color covers the component, from 0% (`.ghost`) to 100% (`.solid`). |
179
+ | Cap | The highest fill a component allows. A form field caps an inherited fill at 6%, for example. |
180
+ | Plate | The component's painted background: the fill, mixed over the ground. |
181
+ | Ground | The color the fill is mixed over. Usually the page itself shows through; a few components set their own, such as the light intent tint under `.kbd` and `.code`. |
182
+ | Edge | The border around the component. It is separate from rules, the lines inside a table. |
183
+ | Ink | A color used to draw lines: the edge, a table's rules, a checkbox's mark. "Text ink" means the color of text printed on a plate. |
184
+ | Material | What an aesthetic changes: corner radius and shape, border width and style, shadow, and transparency. |
185
+ | Slab | A hard, unblurred shadow offset down and to one side, as `.neobrutalism` and `.chunky-tile` draw. |
186
+ | Elevation | How much of the shadow in scope an element takes: none (`.flat`), one unit (`.raised`), or two (`.floating`). |
38
187
 
39
- | Category | Controls | Reference |
40
- | ------------ | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
41
- | Color | The palette: primary, accent, success, warning, destructive, info, text, borders, surfaces. | [Usage → Theming](./usage/theming.md#color-tokens) |
42
- | Intent | Which color slot a component reads once an intent class is applied. | [Usage → Theming](./usage/theming.md#intent-tokens) |
43
- | Foundation | Layout, shape, motion, focus, depth, and layering defaults shared across components. | [Usage → Theming](./usage/theming.md#foundation-tokens) |
44
- | Presentation | How much of an intent a component shows — fill and border percentages. | [Usage → Customizing](./usage/customizing.md#presentation-tokens) |
45
- | Material | What a component is made of — radius, border width, shadow geometry, translucency. | [Usage → Customizing](./usage/customizing.md#material-tokens) |
46
- | Aesthetic | Per-aesthetic knobs such as `--pixel-unit` or `--tile-lift`. | [Usage → Customizing](./usage/customizing.md#aesthetic-tokens) |
188
+ ## Tokens behind the classes
47
189
 
48
- Color and foundation tokens are the ones most apps touch first, to match a brand palette or spacing scale. Intent, presentation, and material tokens are lower-level: components read them, and only presentation classes, aesthetic classes, or a consumer override should set them.
190
+ Every class reads CSS custom properties, called tokens, so you can change the result without rewriting a class:
49
191
 
50
- ## Theme selection
192
+ | Kind | Controls | Where it is listed |
193
+ | ------------ | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
194
+ | Color | The palette: intent colors, text, borders, and backgrounds, for light and dark. | [Theming → Color tokens](./usage/theming.md#color-tokens) |
195
+ | Foundation | Layout widths and gaps, corner radii, control height, focus, motion. | [Theming → Foundation tokens](./usage/theming.md#foundation-tokens) |
196
+ | Intent | The color slots a component reads after an intent class picks a role. | [Theming → Intent tokens](./usage/theming.md#intent-tokens) |
197
+ | Presentation | The fill and border percentages the presentation classes set. | [Customizing → Presentation tokens](./usage/customizing.md#presentation-tokens) |
198
+ | Material | Radius, border width, shadow geometry, and transparency. | [Customizing → Material tokens](./usage/customizing.md#material-tokens) |
199
+ | Aesthetic | One knob per aesthetic, such as `--pixel-unit` or `--tile-lift`. | [Customizing → Aesthetic tokens](./usage/customizing.md#aesthetic-tokens) |
51
200
 
52
- The root follows the operating-system `color-scheme` preference until an explicit selector overrides it.
201
+ Color and foundation tokens are what most apps change first, to match a brand. The rest are lower level: components read them, and the presentation and aesthetic classes set them for you.
53
202
 
54
- | Theme | Equivalent selectors |
55
- | ----- | ------------------------------------------------ |
56
- | Light | `.light`, `.theme-light`, `[data-theme="light"]` |
57
- | Dark | `.dark`, `.theme-dark`, `[data-theme="dark"]` |
203
+ ## Limits to know now
58
204
 
59
- - Theme selectors set `color-scheme` and nothing else. Because `color-scheme` inherits, a selector themes its entire subtree.
60
- - With no explicit selector, `:root` uses `color-scheme: light dark`, so the system preference decides.
61
- - A theme selector on `:root` overrides the system preference in either direction.
62
- - A nested explicit selector overrides an inherited theme, so the nearest themed ancestor controls that subtree at any depth.
63
- - If conflicting light and dark selectors are placed on the same element, the dark declaration wins because it appears later with equal specificity. Do not rely on this conflict behavior; apply one theme per element.
64
- - Component colors resolve from tokens or `currentColor`, so they follow the theme without separate dark-variant rules, with no exception: every glyph the package draws is a `currentColor` mask. Icon artwork a consumer brings is theirs to theme.
65
- - The Tailwind source entrypoints' `dark:` variant tracks this rule for the explicit-selector-versus-system-preference choice: it fires under an explicit dark selector, or under the system preference when the subtree carries no explicit selector at all. It does not track the previous rule the same way: that one holds because `color-scheme` inherits, so the nearest declaration always wins regardless of depth, while `dark:` matches by selector -- `.dark *` matches every descendant of a `.dark` element, with no way to stop at a nearer `.light` in between. A `.light` subtree nested inside `.dark` themes its tokens correctly but still matches `dark:`'s explicit arm. See [Setup → Dark variant](./setup.md#dark-variant).
205
+ - **Intent does not pass down.** Write it on each element that shows it. The only exception is table rows.
206
+ - **Classes are styling only.** `<div class="btn">` looks like a button but cannot be focused or pressed with a keyboard. Use `<button>` or `<a href>`, and see [Accessibility](./accessibility.md).
207
+ - **A combination the docs do not describe is not supported.** It may render, but it can change in any release; see [Introduction → What counts as supported](./index.md#what-counts-as-supported).
66
208
 
67
- Setting `color-scheme` yourself on an element also re-themes the tokens below it, because that is the only signal the palette reads. This also themes native UI such as scrollbars and form-control internals to match.
209
+ ## Next
68
210
 
69
- This mechanism works from Chrome 123, Safari 17.5, and Firefox 120; the package overall requires Firefox 121 for `:has()` (see [Setup](./setup.md#requirements)).
211
+ The screen has one primary action and one quiet one. [Buttons](./usage/buttons.md) adds the rest: a destructive action for the danger zone, icon buttons, sizes, and disabled states.
@@ -0,0 +1,150 @@
1
+ ---
2
+ title: Accesibilidad
3
+ description: Lo que hace el CSS con el foco, los estados, el movimiento, el contraste, los colores forzados y el texto de derecha a izquierda, y lo que tu aplicación todavía les debe a sus usuarios.
4
+ order: 5
5
+ source: dc1a745e9e6853a31ca4a8cf7a334031bab1ec7d
6
+ ---
7
+
8
+ # Accesibilidad
9
+
10
+ La pantalla de ajustes está construida, y el CSS ha hecho su parte por el camino: cada campo muestra dónde está el foco, un email inválido se vuelve rojo y el spinner se detiene para los usuarios que piden menos movimiento. El resto depende de tu HTML y tu JavaScript. Este paquete da estilo a los estados; no aporta elementos semánticos, atributos ARIA, comportamiento de teclado, gestión del foco, validación ni el momento de los anuncios.
11
+
12
+ Esta página enumera las dos mitades: lo que aporta el CSS y lo que tu aplicación tiene que añadir.
13
+
14
+ ## Lo que aporta el CSS
15
+
16
+ ### Foco y estado
17
+
18
+ | Característica | Comportamiento |
19
+ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
20
+ | `:focus-visible` | Un contorno de foco en cada elemento, dibujado con `--focus-ring`, `--focus-ring-width` y `--focus-ring-offset`. |
21
+ | Foco en controles de formulario | `.ipt`, `.textarea` y `.select` dibujan el contorno de foco y cambian su borde al color de la intención. El texto escrito en un campo con una clase de intención usa el tono legible de esa intención, `--intent-strong`. |
22
+ | Controles inválidos | `aria-invalid="true"` en un control de formulario vuelve destructivos su borde, su color de foco y el texto escrito, este último en el tono legible destructivo. |
23
+ | Controles deshabilitados | `disabled`, `aria-disabled="true"`, `data-disabled` y `.disabled` muestran el cursor y la opacidad de deshabilitado, y un control deshabilitado no reacciona al hover, tampoco dentro de un `.input-group`. |
24
+ | Estado abierto | `data-state="open"` en un `.tooltip` muestra su burbuja sin hover ni foco, y `data-state="closed"` la oculta aunque tenga hover o foco. Ningún otro componente lee ninguno de los dos. |
25
+ | `<dialog>` nativo | Un `<dialog>` con `.card`, `.panel` o `.surface` permanece oculto hasta que se abre, y se abre centrado. Un margen que pongas en el diálogo, como utilidad o en tu propio CSS, sigue sobrescribiendo el centrado. Los demás diálogos no se tocan. Atrapar el foco, cerrar con Escape y dejar inerte la página de detrás es cosa de tu aplicación. |
26
+
27
+ ### Contenido visualmente oculto
28
+
29
+ `.visually-hidden` oculta contenido en pantalla y lo mantiene para los lectores de pantalla, como hace el `<caption>` de la tabla de claves de API en [Contenido y layout → Tablas](./usage/content-and-layout.md#tablas). Viene con las utilidades de layout: en `.`, `./native`, `./tw`, `./tw/native` y `./tw/utilities`. No está en `./components` ni en los puntos de entrada de componentes `./tw/components` y `./tw/*`.
30
+
31
+ ### Límites de los controles
32
+
33
+ WCAG 1.4.11 pide que el límite de un control que necesitas ver para usarlo tenga un contraste de al menos 3:1 con lo que lo rodea.
34
+
35
+ | Característica | Comportamiento |
36
+ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
+ | Controles de texto en reposo | El borde de un control de texto reposa más claro que el borde completo de su intención, por debajo de 3:1 a propósito, para que el hover y el foco tengan un tono más intenso al que cambiar. |
38
+ | Toggles | `.checkbox`, `.radio` y `.switch` dibujan su borde completo, porque el borde es lo único que muestra una casilla sin marcar. Un `.switch` con su propio `.edgeless` es la excepción, más abajo. |
39
+ | `.edgeless` desde un contenedor | Lo ignoran todos los controles de texto y toggles: un contenedor no puede quitar el borde de un campo o toggle que contiene. |
40
+ | `.edgeless` en el control | `.ipt`, `.textarea`, `.select` y `.switch` pierden su borde y dejan de cumplir 1.4.11 en reposo. `.switch.ghost` conserva su borde incluso entonces, porque sin relleno y sin borde nada mostraría el carril. |
41
+ | `.checkbox`, `.radio` | Siempre dibujan su borde, venga `.edgeless` de un contenedor o lo lleven ellos mismos. `.edgeless` en ellos no está soportado. |
42
+ | Carril de progreso | A propósito, la parte rellena lleva el valor y el carril es un fondo discreto. El carril por defecto, `.soft.edgeless`, mide aproximadamente de 1.1:1 a 1.3:1 frente a la página. La parte rellena mide al menos 3:1 frente a ese carril para todas las intenciones excepto warning en claro (unos 2.7:1) e info en oscuro (unos 2.9:1). Donde el propio carril deba cumplir 1.4.11, usa `.ghost.edged` con una clase de intención; consulta [Contornos de progreso](#contornos-de-progreso) más abajo. |
43
+
44
+ ### Contornos de progreso
45
+
46
+ En un `.progress.ghost.edged`, el carril es la página, y tanto su contorno como la parte rellena se dibujan en el color de la intención. Medido frente a la página, sin estética:
47
+
48
+ | Intención | Página clara | Página oscura | Cumple 3:1 |
49
+ | -------------- | ------------ | ------------- | ----------------------------------------------------------------------------- |
50
+ | `.primary` | 18.96:1 | 18.96:1 | Sí |
51
+ | `.secondary` | 7.47:1 | 7.63:1 | Sí |
52
+ | `.success` | 5.14:1 | 3.69:1 | Sí |
53
+ | `.warning` | 3.06:1 | 6.20:1 | Sí |
54
+ | `.destructive` | 5.80:1 | 3.27:1 | Sí |
55
+ | `.info` | 6.17:1 | 3.07:1 | Sí |
56
+ | Sin intención | 2.48:1 | 1.91:1 | No: el contorno no cumple, aunque la parte rellena, en el color del texto, sí |
57
+
58
+ Sin clase de intención, el contorno es el gris discreto de los bordes, `--color-border`. Para que un carril neutro cumpla 1.4.11, dale a la barra una clase de intención, o define `--progress-edge` con un color más intenso, como `var(--color-accent)`, que mide 7.47:1 en una página clara y 7.63:1 en una oscura. Warning en una página clara e info en una oscura superan 3:1 por poco margen, así que vuelve a medir si cambias esos colores.
59
+
60
+ ### Movimiento y transparencia
61
+
62
+ | Característica | Comportamiento |
63
+ | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
64
+ | Movimiento reducido, componentes | Con `prefers-reduced-motion: reduce`, cada componente detiene sus propias transiciones y animaciones: el brillo del skeleton y del progreso, la barra indeterminada, el tooltip, las marcas de los toggles y la pulsación. |
65
+ | Movimiento reducido, toda la página | El reset también acorta todas las demás animaciones y transiciones de la página. |
66
+ | Transparencia reducida | Con `prefers-reduced-transparency: reduce`, `.glass` y `.glass-liquid` pierden su desenfoque y su lente y se vuelven opacos. |
67
+
68
+ La regla de movimiento reducido de cada componente viene con el componente, así que cada punto de entrada que lo incluye respeta el movimiento reducido sin el reset, incluidos `@codenhub/styles/components`, `@codenhub/styles/tw/components` y cada punto de entrada de componente `/tw/*`. Los puntos de entrada completo y native añaden la regla del reset para toda la página.
69
+
70
+ La regla del reset es `!important` dentro de la capa `base`, y un `!important` con capa gana a uno sin capa, así que tu propio `!important` no puede volver a activar una animación. Para mantener una en marcha para los usuarios que piden movimiento reducido, como un spinner de subida que consideres esencial, declárala `!important` en una capa ordenada antes de `base`. La primera sentencia `@layer` que lee el navegador fija el orden, así que la tuya va antes del paquete:
71
+
72
+ ```css
73
+ @layer essential-motion, theme, base, components, utilities;
74
+ @import "@codenhub/styles";
75
+
76
+ @layer essential-motion {
77
+ @media (prefers-reduced-motion: reduce) {
78
+ .upload-spinner {
79
+ animation-duration: 1s !important;
80
+ animation-iteration-count: infinite !important;
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ Respetar el movimiento reducido no es todo lo que se pide. El movimiento que sigue en marcha junto al contenido, como un brillo que queda en una tarjeta después de que ha cargado, necesita una forma de detenerlo para todos los usuarios; consulta [Feedback → Animación que no se detiene](./usage/feedback.md#animación-que-no-se-detiene).
87
+
88
+ ### Color y contraste
89
+
90
+ Las mediciones de abajo corresponden a los colores incluidos. En cuanto cambies un token de color, vuelve a medir tus propios pares; [Temas → Cambiar el color de marca](./usage/theming.md#cambiar-el-color-de-marca) muestra qué pares comprobar.
91
+
92
+ | Característica | Comportamiento |
93
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
94
+ | Etiquetas rellenas | La etiqueta `.solid` de cada intención cumple 4.5:1 (WCAG 1.4.3) como texto normal, en ambos temas. La más baja es success, con 5.14:1. |
95
+ | Texto de warning | `--color-warning-contrast` es casi negro, no el color de la página, porque un ámbar lo bastante oscuro para llevar texto blanco ya no parece ámbar. |
96
+ | Rellenos parciales | El color de texto de contraste solo aparece en rellenos por encima de la mitad de intensidad, así que el relleno limitado de un control de texto conserva el color de texto propio de la intención. |
97
+ | Color de intención en oscuro | En modo oscuro, una etiqueta `.soft` o `.ghost` usa el tono `-300` de su intención, así que conserva su matiz en lugar de volverse blanca. |
98
+ | Marcas de los toggles | Una marca activada mide al menos 3:1 frente a cada relleno que su presentación pueda darle, en ambos temas. |
99
+ | Rellenos soft con borde | `.edged` en un `.alert`, `.panel`, `.badge`, `.kbd`, `.code` o `.pre` `.soft` dibuja un borde que mide menos de 3:1 frente al relleno del 12% en algunas intenciones, cuáles depende del tema. Mide el par antes de confiar en ese borde como límite de un control. |
100
+
101
+ ### Colores forzados y dirección
102
+
103
+ | Característica | Comportamiento |
104
+ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
105
+ | Colores forzados | Con `forced-colors: active`, los bordes, los estados activados y el chevron de un `.select` siguen visibles, dibujados con colores del sistema, bajo cualquier estética. Una estética que dibuja su borde como una sombra interior, como `.pixel`, dibuja en su lugar un borde real. |
106
+ | Dirección del texto | Con `dir="rtl"`, la barra de las citas, el icono de la alerta, el relleno del progreso, el divisor vertical, la perilla del switch, la alineación de las tablas y el chevron de un select cambian de lado. No hace falta ninguna clase. |
107
+
108
+ Con colores forzados, `.text-control`, `.ipt`, `.textarea`, `.select` y los toggles muestran un contorno de foco `Highlight` de 2px. El punto de entrada native da el mismo contorno a los inputs de texto, selects, textareas, checkboxes y radios sin clase.
109
+
110
+ Los checkboxes, radios y switches usan los colores del sistema `Canvas`, `CanvasText`, `Highlight` y `HighlightText`, así que activado y desactivado siguen siendo distinguibles: un toggle activado se rellena con `Highlight` y su marca es `HighlightText`, tanto en las clases como en el punto de entrada native. La forma, el tamaño y el espaciado no cambian.
111
+
112
+ ## Lo que hace falta fuera del CSS
113
+
114
+ Usa el elemento HTML que corresponde a lo que hace el componente, y añade el comportamiento que el CSS no puede dar.
115
+
116
+ | Interfaz | Lo que añade tu aplicación |
117
+ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
118
+ | Botones | `<button>` para acciones y `<a href>` para navegación. Un nombre accesible, como `aria-label`, en cada `.btn.icon`. |
119
+ | Formularios | Un `<label>` para cada control, el `type` correcto, validación y `aria-describedby` enlazando pistas y errores. Mantén las pistas y los errores fuera del `<label>`, y dale a un `.switch` `role="switch"`. |
120
+ | Alertas | `role="status"` para una confirmación como "Perfil guardado", o `role="alert"` para un error que necesita atención inmediata. |
121
+ | Toasts | Una región live, una forma de cerrarlo, reglas de foco y una pausa en cualquier temporizador. |
122
+ | Tooltips | Un `id` real y `role="tooltip"` en la burbuja, referenciado desde el `aria-describedby` del disparador. El cierre con Escape escribiendo `data-state="closed"`; consulta [Tooltips](./usage/tooltips.md#hover-permanencia-y-escape). La burbuja ya admite hover. |
123
+ | Progreso | Un elemento `<progress>`, o `role="progressbar"` o `role="meter"` con valores ARIA, cuando el valor debe anunciarse. |
124
+ | Skeletons | `aria-hidden="true"` en los elementos visuales de carga, incluido un spinner que aportes tú, y el estado de carga anunciado de otra forma cuando haga falta. |
125
+ | Movimiento continuo | Una forma de pausar, detener u ocultar el movimiento que no es esencial; consulta [Feedback → Animación que no se detiene](./usage/feedback.md#animación-que-no-se-detiene). |
126
+ | Popovers, modales | Atrapar el foco, cerrar con Escape, un fondo inerte, etiquetas y roles. |
127
+
128
+ ## Atributos de estado
129
+
130
+ Prefiere los atributos nativos:
131
+
132
+ ```html
133
+ <button class="btn primary" disabled>Saving…</button> <input class="ipt" type="email" aria-invalid="true" aria-describedby="email-error" />
134
+ ```
135
+
136
+ Usa atributos ARIA o data donde el elemento o tu librería de componentes no tenga uno nativo:
137
+
138
+ ```html
139
+ <a class="btn secondary" aria-disabled="true">Export data</a>
140
+ <span class="tooltip" data-state="open">
141
+ <button type="button" class="tooltip-icon" aria-label="About public profiles" aria-describedby="public-profile-help">?</button>
142
+ <span class="tooltip-bubble" role="tooltip" id="public-profile-help">Anyone with the link can see your name and photo.</span>
143
+ </span>
144
+ ```
145
+
146
+ `aria-disabled="true"` indica a las tecnologías de asistencia que el control está deshabilitado, pero no impide un clic ni una pulsación de tecla. Usa el atributo `disabled`, o detén la acción en JavaScript.
147
+
148
+ ## Siguiente paso
149
+
150
+ Con esto termina el orden de lectura. La [Introducción](./index.md) enlaza todas las páginas, y [Composición](./usage/composing.md), [Personalización](./usage/customizing.md) y [Contenido y layout](./usage/content-and-layout.md) son las páginas de consulta para más adelante.