From 755d0b9d80e60b6f29ab66bd894203b33d2b58c5 Mon Sep 17 00:00:00 2001 From: Farhan Date: Tue, 27 Oct 2026 20:14:32 +0000 Subject: [PATCH 1/4] Fix dark-mode contrast in the layout component demos The stack, box, spacer and aspect ratio demos use fixed light CSS background colors but inherit the theme text color, so in dark mode the labels rendered near-white on pastel boxes. Pin the text color on those boxes. Claude-Session: https://claude.ai/code/session_01LwJUCUDZhZY71q8Azr37BQ --- docs/app/news/+layout-demos-dark-mode.bugfix.md | 1 + docs/library/layout/aspect_ratio.md | 4 ++++ docs/library/layout/box.md | 2 ++ docs/library/layout/spacer.md | 6 +++--- docs/library/layout/stack.md | 14 ++++++++++++++ 5 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 docs/app/news/+layout-demos-dark-mode.bugfix.md diff --git a/docs/app/news/+layout-demos-dark-mode.bugfix.md b/docs/app/news/+layout-demos-dark-mode.bugfix.md new file mode 100644 index 00000000000..6de8b59073d --- /dev/null +++ b/docs/app/news/+layout-demos-dark-mode.bugfix.md @@ -0,0 +1 @@ +Fix unreadable light-on-light text in the stack, box, spacer and aspect ratio layout demos when the docs are viewed in dark mode. diff --git a/docs/library/layout/aspect_ratio.md b/docs/library/layout/aspect_ratio.md index 3dd943ef63e..ee6ae6c1bd0 100644 --- a/docs/library/layout/aspect_ratio.md +++ b/docs/library/layout/aspect_ratio.md @@ -23,6 +23,7 @@ rx.grid( rx.box( "Widescreen 16:9", background_color="papayawhip", + color="black", width="100%", height="100%", ), @@ -32,6 +33,7 @@ rx.grid( rx.box( "Letterbox 4:3", background_color="orange", + color="black", width="100%", height="100%", ), @@ -41,6 +43,7 @@ rx.grid( rx.box( "Square 1:1", background_color="green", + color="black", width="100%", height="100%", ), @@ -50,6 +53,7 @@ rx.grid( rx.box( "Portrait 5:7", background_color="lime", + color="black", width="100%", height="100%", ), diff --git a/docs/library/layout/box.md b/docs/library/layout/box.md index 14f16aceca2..ccf927f2574 100644 --- a/docs/library/layout/box.md +++ b/docs/library/layout/box.md @@ -20,6 +20,7 @@ rx.box( rx.box( "CSS color", background_color="yellow", + color="black", border_radius="2px", width="20%", margin="4px", @@ -28,6 +29,7 @@ rx.box( rx.box( "CSS color", background_color="orange", + color="black", border_radius="5px", width="40%", margin="8px", diff --git a/docs/library/layout/spacer.md b/docs/library/layout/spacer.md index 0d9d1b01723..f316cebcf9d 100644 --- a/docs/library/layout/spacer.md +++ b/docs/library/layout/spacer.md @@ -13,11 +13,11 @@ Creates an adjustable, empty space that can be used to tune the spacing between ```python demo rx.flex( - rx.center(rx.text("Example"), bg="lightblue"), + rx.center(rx.text("Example"), bg="lightblue", color="black"), rx.spacer(), - rx.center(rx.text("Example"), bg="lightgreen"), + rx.center(rx.text("Example"), bg="lightgreen", color="black"), rx.spacer(), - rx.center(rx.text("Example"), bg="salmon"), + rx.center(rx.text("Example"), bg="salmon", color="black"), width="100%", ) ``` diff --git a/docs/library/layout/stack.md b/docs/library/layout/stack.md index 423ccc1802e..3b50a32367b 100644 --- a/docs/library/layout/stack.md +++ b/docs/library/layout/stack.md @@ -56,18 +56,21 @@ rx.flex( rx.box( "Example", bg="orange", + color="black", border_radius="3px", width="20%", ), rx.box( "Example", bg="lightblue", + color="black", border_radius="3px", width="30%", ), rx.box( "Example", bg="lightgreen", + color="black", border_radius="3px", width="50%", ), @@ -78,18 +81,21 @@ rx.flex( rx.box( "Example", bg="orange", + color="black", border_radius="3px", width="20%", ), rx.box( "Example", bg="lightblue", + color="black", border_radius="3px", width="30%", ), rx.box( "Example", bg="lightgreen", + color="black", border_radius="3px", width="50%", ), @@ -108,24 +114,28 @@ rx.hstack( rx.box( "Example", bg="orange", + color="black", border_radius="3px", width="10%", ), rx.box( "Example", bg="yellow", + color="black", border_radius="3px", width="10%", ), rx.box( "Example", bg="lightblue", + color="black", border_radius="3px", width="10%", ), rx.box( "Example", bg="lightgreen", + color="black", border_radius="3px", width="60%", ), @@ -141,24 +151,28 @@ rx.vstack( rx.box( "Example", bg="orange", + color="black", border_radius="3px", width="40%", ), rx.box( "Example", bg="yellow", + color="black", border_radius="3px", width="60%", ), rx.box( "Example", bg="lightblue", + color="black", border_radius="3px", width="80%", ), rx.box( "Example", bg="lightgreen", + color="black", border_radius="3px", width="100%", ), From 1d911cda53eb3e67f470ad08792854b53b0b943e Mon Sep 17 00:00:00 2001 From: Farhan Date: Tue, 27 Oct 2026 20:21:57 +0000 Subject: [PATCH 2/4] Use white text on the green aspect ratio tile and add a contrast regression test Black on CSS green is about 4.09:1, below the 4.5:1 target; white reads better there. The test scans the four layout demos and fails when a box with a fixed named background has no explicit text color. Claude-Session: https://claude.ai/code/session_01LwJUCUDZhZY71q8Azr37BQ --- docs/app/tests/test_layout_demo_contrast.py | 33 +++++++++++++++++++++ docs/library/layout/aspect_ratio.md | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 docs/app/tests/test_layout_demo_contrast.py diff --git a/docs/app/tests/test_layout_demo_contrast.py b/docs/app/tests/test_layout_demo_contrast.py new file mode 100644 index 00000000000..4cdd62bbf28 --- /dev/null +++ b/docs/app/tests/test_layout_demo_contrast.py @@ -0,0 +1,33 @@ +"""Regression coverage for fixed-color layout demos staying readable in dark mode.""" + +import re +from pathlib import Path + +import pytest + +DOCS = Path(__file__).parents[2] + +# Named CSS backgrounds the layout demos use; none of them adapt to the theme, +# so each box must pin its own text color instead of inheriting the theme's. +FIXED_BACKGROUND = re.compile( + r'^(?P\s*)(?:bg|background_color)="(?:[a-z]+)",?\s*$', re.MULTILINE +) +INLINE_FIXED_BACKGROUND = re.compile(r'bg="[a-z]+"(?P[^)]*)\)') + + +@pytest.mark.parametrize( + "doc", + ["layout/stack.md", "layout/box.md", "layout/spacer.md", "layout/aspect_ratio.md"], +) +def test_fixed_color_boxes_pin_a_text_color(doc): + """Every box with a fixed CSS background also sets an explicit text color.""" + source = (DOCS / "library" / doc).read_text() + for match in FIXED_BACKGROUND.finditer(source): + following = source[match.end() : match.end() + 200] + assert re.match(r'\s*color="', following), ( + f"{doc}: {match.group(0).strip()} has no explicit text color" + ) + for match in INLINE_FIXED_BACKGROUND.finditer(source): + assert 'color="' in match.group("rest"), ( + f"{doc}: {match.group(0)} has no explicit text color" + ) diff --git a/docs/library/layout/aspect_ratio.md b/docs/library/layout/aspect_ratio.md index ee6ae6c1bd0..11ac9d07446 100644 --- a/docs/library/layout/aspect_ratio.md +++ b/docs/library/layout/aspect_ratio.md @@ -43,7 +43,7 @@ rx.grid( rx.box( "Square 1:1", background_color="green", - color="black", + color="white", width="100%", height="100%", ), From 717507cb8b8e2b5c877a72cd7d6f4f9a5e106f7a Mon Sep 17 00:00:00 2001 From: Farhan Date: Tue, 27 Oct 2026 20:23:03 +0000 Subject: [PATCH 3/4] Pin text color on the inline red stack boxes too Claude-Session: https://claude.ai/code/session_01LwJUCUDZhZY71q8Azr37BQ --- docs/library/layout/stack.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/library/layout/stack.md b/docs/library/layout/stack.md index 3b50a32367b..fc21f44cb58 100644 --- a/docs/library/layout/stack.md +++ b/docs/library/layout/stack.md @@ -110,7 +110,7 @@ rx.flex( ```python demo rx.hstack( - rx.box("Example", bg="red", border_radius="3px", width="10%"), + rx.box("Example", bg="red", color="black", border_radius="3px", width="10%"), rx.box( "Example", bg="orange", @@ -147,7 +147,7 @@ rx.hstack( ```python demo rx.vstack( - rx.box("Example", bg="red", border_radius="3px", width="20%"), + rx.box("Example", bg="red", color="black", border_radius="3px", width="20%"), rx.box( "Example", bg="orange", From cac21f32aeeab95d3b0158bf11d753b1984b432e Mon Sep 17 00:00:00 2001 From: Farhan Date: Tue, 27 Oct 2026 20:28:06 +0000 Subject: [PATCH 4/4] Check the whole component call for a text color in the layout contrast test The test now finds every bg/background_color prop, inline or not, and looks for color anywhere in the enclosing call rather than requiring a fixed prop order. Claude-Session: https://claude.ai/code/session_01LwJUCUDZhZY71q8Azr37BQ --- docs/app/tests/test_layout_demo_contrast.py | 56 +++++++++++++++------ 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/docs/app/tests/test_layout_demo_contrast.py b/docs/app/tests/test_layout_demo_contrast.py index 4cdd62bbf28..9538b3d98be 100644 --- a/docs/app/tests/test_layout_demo_contrast.py +++ b/docs/app/tests/test_layout_demo_contrast.py @@ -5,14 +5,44 @@ import pytest -DOCS = Path(__file__).parents[2] +DOCS = Path(__file__).resolve().parents[2] -# Named CSS backgrounds the layout demos use; none of them adapt to the theme, -# so each box must pin its own text color instead of inheriting the theme's. -FIXED_BACKGROUND = re.compile( - r'^(?P\s*)(?:bg|background_color)="(?:[a-z]+)",?\s*$', re.MULTILINE -) -INLINE_FIXED_BACKGROUND = re.compile(r'bg="[a-z]+"(?P[^)]*)\)') +# Named CSS backgrounds do not adapt to the theme, so a box using one must pin +# its own text color instead of inheriting the theme's foreground. +FIXED_BACKGROUND = re.compile(r'(?:bg|background_color)="[a-z]+"') + + +def enclosing_call(source: str, index: int) -> str: + """Return the argument text of the component call that contains ``index``. + + Args: + source: The document source. + index: An offset inside the call's argument list. + + Returns: + The text between the call's opening and closing parentheses. + """ + depth = 0 + start = index + while start > 0: + start -= 1 + if source[start] == ")": + depth += 1 + elif source[start] == "(": + if depth == 0: + break + depth -= 1 + depth = 0 + end = start + while end < len(source): + end += 1 + if source[end] == "(": + depth += 1 + elif source[end] == ")": + if depth == 0: + break + depth -= 1 + return source[start + 1 : end] @pytest.mark.parametrize( @@ -20,14 +50,10 @@ ["layout/stack.md", "layout/box.md", "layout/spacer.md", "layout/aspect_ratio.md"], ) def test_fixed_color_boxes_pin_a_text_color(doc): - """Every box with a fixed CSS background also sets an explicit text color.""" + """Every component with a fixed CSS background also sets an explicit text color.""" source = (DOCS / "library" / doc).read_text() for match in FIXED_BACKGROUND.finditer(source): - following = source[match.end() : match.end() + 200] - assert re.match(r'\s*color="', following), ( - f"{doc}: {match.group(0).strip()} has no explicit text color" - ) - for match in INLINE_FIXED_BACKGROUND.finditer(source): - assert 'color="' in match.group("rest"), ( - f"{doc}: {match.group(0)} has no explicit text color" + call = enclosing_call(source, match.start()) + assert re.search(r'\bcolor="', call), ( + f"{doc}: {match.group(0)} has no explicit text color in {call.strip()!r}" )