Skip to content

* css-icons: restore the caret opacity at rest - #242

Merged
catouse merged 2 commits into
dev_optimize_css_libsfrom
dev_optimize_caret_opacity
Aug 31, 2026
Merged

* css-icons: restore the caret opacity at rest#242
catouse merged 2 commits into
dev_optimize_css_libsfrom
dev_optimize_caret_opacity

Conversation

@Lwrless

@Lwrless Lwrless commented Aug 21, 2026

Copy link
Copy Markdown
Member

Stacked on #240. Base branch is dev_optimize_css_libs, so this PR's diff shows only the caret work. It will need retargeting to dev_optimize if #240's branch is not deleted on merge.

Three defects, all left behind by one commit.

aaf34e96dd (2024-03-24, "css-icons: change caret shape from angle to chevron") rewrote the shared caret rule. Before it:

.caret, .caret-down, .caret-left, .caret-right, .caret-up {
    @apply -w-0 -h-0 -inline-block;
    border: var(--caret-size, 4px) solid transparent;   /* the triangle */
    opacity: var(--caret-opacity, .5);                  /* all five variants */
}

The reshape kept the geometry and dropped both var() reads. The commit message describes a shape change and nothing else.

# Defect
F-1 @zui/tree set --caret-opacity: .3 on .tree-toggle (13ee4449eb, 2023-06-30, "change toggle icon opacity"). Live and visible when written; dead since the reshape.
F-2 Carets stopped dimming at rest everywhere — 71 of them, all at opacity: 1, where the default had been .5.
F-3 .disabled .caret / .readonly .caret silently lost coverage of the four directional variants. It targeted bare .caret only, which was correct while the shared rule carried the default for all five.

This PR fixes F-2 and F-3, in @zui/css-icons only. F-1 — tree's dead override — is removed in #241, which touches no file this PR touches.

Restores opacity: var(--caret-opacity) on the shared five-variant rule, so --caret-opacity now means the at-rest opacity, and extends the .disabled / .readonly rule to all five variants.

Why tree's .3 is not revived (implemented in #241): it was tuned in 2023 for the old caret — a filled 4px triangle. The chevron that replaced it is a 1px stroke, and the same number reads far lighter on it. Rendered side by side in both themes, .3 on the chevron is faint enough to read as disabled rather than secondary, which is the wrong signal for a tree expander. Tree toggles should use the .5 default like every other caret.

Why the .disabled rule is not redundant with the restored default: @zui/utilities applies .disabled * {opacity: var(--opacity-disabled)} at the same specificity as the base caret rule. Without pinning, a caret inside a disabled container would resolve to .7brighter than the .5 it shows when enabled.

Measurements

Before, injecting all five variants into a wrapper:

wrapper .caret directional variants
none 1 1
.disabled 0.5 0.7
.readonly 0.5 1

After — every variant identical in every state:

wrapper all five
none 0.5
.disabled 0.5 (× 0.7 container = 0.35 effective)
.readonly 0.5
ancestor sets --caret-opacity: .9 0.9

Re-tallied across the consumer dev pages, matching batch 4's census exactly — 71 carets, zero console errors:

lib n opacity on this branch
picker 11 0.5
dropdown 22 0.5
nav 27 0.5
menu 7 0.5
tree 4 0.3 — tree's own override still present here

Tree reads 0.3 on this branch alone because its --caret-opacity: .3 survives until #241 lands; with both merged, all 71 sit at 0.5. Merging #241 first avoids that transient, though nothing breaks in the other order.

Docs page demo verified on the built site: 0.5 default, 1 and 0.3 via ancestor override, disabled pinned at 0.5 inside a 0.7 container.

Rendering impact

This is a deliberate visual change: every caret in the product goes from fully opaque to .5. That is the point of the PR — restoring a design the 2024 reshape dropped by accident — but it is the one item in this follow-up wave that is not rendering-neutral, and it deserves a look rather than a rubber stamp.

Validation

pnpm lint, pnpm typecheck, pnpm check (9 test files / 60 tests, 4 skills tests), pnpm build -- --lib=css-icons --noMinify, pnpm docs:prepare -- --copy and pnpm docs:build all green.

CI on this repo is currently failing for every PR with "The job was not started because your account is locked due to a billing issue" — unrelated to this change.

`aaf34e96dd` (2024-03-24, "change caret shape from angle to chevron") rewrote the
shared caret rule and, along with the triangle geometry, dropped
`opacity: var(--caret-opacity, .5)` from it. The commit message describes a shape
change only. Since then every caret in the product has rendered fully opaque — 71
of them across `picker`, `dropdown`, `nav`, `menu` and `tree` — where the design
had them at `.5`, reading as a secondary element next to their label.

Restore the declaration on the shared five-variant rule. `--caret-opacity` now
means the at-rest opacity rather than a disabled-only value, so the `:root`
comment is updated to match.

Extend the `.disabled` / `.readonly` rule to the four directional variants. It
covered bare `.caret` only, which was correct while the shared rule carried the
default for all five, but became a coverage gap the moment that default was
deleted: measured before this change, a caret inside `.disabled` resolved to
`.5` while a `.caret-down` beside it resolved to `.7`.

That rule is not redundant with the restored default. `@zui/utilities` applies
`.disabled *  {opacity: var(--opacity-disabled)}` at the same specificity as the
base caret rule, so without pinning, a caret inside a disabled container would
resolve to `.7` — brighter than the `.5` it shows when enabled.

Measured after, on every variant and in every state: `.5` at rest, `.5` pinned
inside `.disabled` and `.readonly`, and an ancestor override reaching bare and
directional carets alike.
The docs described `--caret-opacity` as the opacity of a caret inside a
`disabled` or `readonly` element, which was accurate for the code as it stood but
described a leftover rather than a design. Now that the variable is the at-rest
opacity, rewrite the section around what it actually controls.

- The example demonstrates the override that consumers will reach for — setting
  `--caret-opacity` on an ancestor — instead of three carets that only differed
  by state.
- `disabled` and `readonly` are described as pinning the opacity rather than
  dimming it, with the reason: `.disabled *` would otherwise make a caret in a
  disabled container brighter than one outside it.
- Dropped the pointer to `@zui/tree` setting `.3` on `.tree-toggle`. That
  declaration is dead — nothing has read it since the 2024 caret reshape — and is
  removed separately in the branch that clears out tree's orphaned caret
  variables, so the docs should not present it as a worked example.
@Lwrless
Lwrless force-pushed the dev_optimize_caret_opacity branch from cc5acad to 1784aab Compare August 22, 2026 05:21
@catouse
catouse marked this pull request as ready for review August 31, 2026 02:47
@catouse
catouse merged commit 974b541 into dev_optimize_css_libs Aug 31, 2026
0 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants