Skip to content

Fix light mode secondary/tertiary colors rendering as white (#854)#878

Merged
twostraws merged 1 commit intotwostraws:mainfrom
RomanticD:fix/issue-854-light-mode-secondary-color-is-white
Apr 24, 2026
Merged

Fix light mode secondary/tertiary colors rendering as white (#854)#878
twostraws merged 1 commit intotwostraws:mainfrom
RomanticD:fix/issue-854-light-mode-secondary-color-is-white

Conversation

@RomanticD
Copy link
Copy Markdown
Contributor

Fixes #854.

Summary

.foregroundStyle(.secondary) (and .tertiary) rendered as pure white in light mode, making text invisible on the default white background. The root cause is an initializer-overload mismatch in Theme-DefaultImplementation.swift:

// Before
var secondary: Color {
    colorScheme == .dark ?
    Color(red: 222, green: 226, blue: 230, opacity: 0.75) :
    Color(red: 33,  green: 37,  blue: 41,  opacity: 0.75)
}

0.75 is a Double, not a Percentage, so Swift picks the Double RGB initializer that treats each channel as a 0–1 float and multiplies by 255:

public init(red: Double, green: Double, blue: Double, opacity: Double = 1) {
    let intRed   = Int(red   * 255)  // 33 * 255 = 8415
    let intGreen = Int(green * 255)  // 37 * 255 = 9435
    let intBlue  = Int(blue  * 255)  // 41 * 255 = 10455
    ...
}

The emitted CSS for --bs-secondary becomes rgb(8415 9435 10455 / 75%). Browsers clamp each channel to 255, so the color resolves to white (reported in the issue as "50 000+" channel values — same bug, seen through the devtools rounding).

Dark mode happened to look OK because white text on a dark background is still readable (it just wasn't the intended 75%-opacity light grey).

Fix

Switch the four affected call sites from Double opacities to Percentage:

// After
Color(red: 222, green: 226, blue: 230, opacity: 75%)
Color(red: 33,  green: 37,  blue: 41,  opacity: 75%)
Color(red: 222, green: 226, blue: 230, opacity: 50%)
Color(red: 33,  green: 37,  blue: 41,  opacity: 50%)

75% / 50% produce a Percentage, which is the only type that matches the integer-RGB initializer's opacity: parameter. The channels stay 33/37/41 and 222/226/230, matching the inline-comment intent (Bootstrap's standard light/dark text colors).

This touches only Theme-DefaultImplementation.swift — the default secondary and tertiary Bootstrap color variables. Custom themes that override secondary/tertiary are unaffected. No behavior change in dark mode beyond finally hitting the intended 75%/50% opacity values instead of white.

Test plan

  • Added regression tests in Tests/IgniteTesting/Themes/ThemeDefaultColors.swift that assert DefaultLightTheme().secondary / DefaultDarkTheme().secondary / .tertiary resolve to the expected RGB + opacity values. The tests fail on main (e.g. color.red → 8415) and pass with this change.
  • swift test — all 1124 tests pass.
  • swiftlint lint — no issues on touched files.
  • swift build — clean.

🤖 Generated with Claude Code

…s#854)

The default `secondary` and `tertiary` colors used `opacity: 0.75` and
`opacity: 0.5` (both `Double`s), which caused Swift to prefer the
`Color(red: Double, green: Double, blue: Double, opacity: Double)`
initializer over the intended
`Color(red: Int, green: Int, blue: Int, opacity: Percentage)` one.

The `Double` init treats its RGB arguments as 0–1 floats and multiplies
by 255, so values like `Color(red: 33, green: 37, blue: 41, opacity: 0.75)`
produced `rgb(8415 9435 10455)` in the generated CSS. Browsers clamp
each channel to 255, so the text rendered as pure white — invisible on a
light background.

Using `75%` / `50%` (a `Percentage`) makes the integer RGB initializer
the unambiguous match, so the channels are preserved as-is.

Adds regression tests covering secondary and tertiary for both default
themes.
@twostraws
Copy link
Copy Markdown
Owner

Thank you!

@twostraws twostraws merged commit 128c26b into twostraws:main Apr 24, 2026
1 check 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.

Light mode secondary color is white

2 participants