Skip to content
This repository was archived by the owner on May 7, 2026. It is now read-only.

Commit 30d177a

Browse files
committed
feat: Add dark mode support to TableWidget
- Updates table_widget.css to use CSS variables for colors where possible. - Adds @media (prefers-color-scheme: dark) block to handle dark mode overrides. - Updates text and background colors to be legible in dark mode. - Adds unit test to verify CSS contains dark mode media query.
1 parent 69fa7f4 commit 30d177a

2 files changed

Lines changed: 122 additions & 70 deletions

File tree

bigframes/display/table_widget.css

Lines changed: 104 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -15,138 +15,172 @@
1515
*/
1616

1717
.bigframes-widget {
18-
display: flex;
19-
flex-direction: column;
18+
display: flex;
19+
flex-direction: column;
2020
}
2121

2222
.bigframes-widget .table-container {
23-
max-height: 620px;
24-
overflow: auto;
23+
max-height: 620px;
24+
overflow: auto;
2525
}
2626

2727
.bigframes-widget .footer {
28-
align-items: center;
29-
/* TODO(b/460861328): We will support dark mode in a media selector once we
30-
* determine how to override the background colors as well. */
31-
color: black;
32-
display: flex;
33-
font-family:
34-
"-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", sans-serif;
35-
font-size: 0.8rem;
36-
justify-content: space-between;
37-
padding: 8px;
28+
align-items: center;
29+
color: var(--colab-primary-text-color, var(--jp-ui-font-color0, black));
30+
display: flex;
31+
font-family:
32+
"-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", sans-serif;
33+
font-size: 0.8rem;
34+
justify-content: space-between;
35+
padding: 8px;
3836
}
3937

4038
.bigframes-widget .footer > * {
41-
flex: 1;
39+
flex: 1;
4240
}
4341

4442
.bigframes-widget .pagination {
45-
align-items: center;
46-
display: flex;
47-
flex-direction: row;
48-
gap: 4px;
49-
justify-content: center;
50-
padding: 4px;
43+
align-items: center;
44+
display: flex;
45+
flex-direction: row;
46+
gap: 4px;
47+
justify-content: center;
48+
padding: 4px;
5149
}
5250

5351
.bigframes-widget .page-indicator {
54-
margin: 0 8px;
52+
margin: 0 8px;
5553
}
5654

5755
.bigframes-widget .row-count {
58-
margin: 0 8px;
56+
margin: 0 8px;
5957
}
6058

6159
.bigframes-widget .page-size {
62-
align-items: center;
63-
display: flex;
64-
flex-direction: row;
65-
gap: 4px;
66-
justify-content: end;
60+
align-items: center;
61+
display: flex;
62+
flex-direction: row;
63+
gap: 4px;
64+
justify-content: end;
6765
}
6866

6967
.bigframes-widget .page-size label {
70-
margin-right: 8px;
68+
margin-right: 8px;
7169
}
7270

7371
.bigframes-widget table {
74-
border-collapse: collapse;
75-
/* TODO(b/460861328): We will support dark mode in a media selector once we
76-
* determine how to override the background colors as well. */
77-
color: black;
78-
text-align: left;
72+
border-collapse: collapse;
73+
color: var(--colab-primary-text-color, var(--jp-ui-font-color0, black));
74+
text-align: left;
7975
}
8076

8177
.bigframes-widget th {
82-
background-color: var(--colab-primary-surface-color, var(--jp-layout-color0));
83-
padding: 0;
84-
position: sticky;
85-
text-align: left;
86-
top: 0;
87-
z-index: 1;
78+
background-color: var(
79+
--colab-primary-surface-color,
80+
var(--jp-layout-color0, white)
81+
);
82+
padding: 0;
83+
position: sticky;
84+
text-align: left;
85+
top: 0;
86+
z-index: 1;
8887
}
8988

9089
.bigframes-widget .bf-header-content {
91-
box-sizing: border-box;
92-
height: 100%;
93-
overflow: auto;
94-
padding: 0.5em;
95-
resize: horizontal;
96-
width: 100%;
90+
box-sizing: border-box;
91+
height: 100%;
92+
overflow: auto;
93+
padding: 0.5em;
94+
resize: horizontal;
95+
width: 100%;
9796
}
9897

9998
.bigframes-widget th .sort-indicator {
100-
padding-left: 4px;
101-
visibility: hidden;
99+
padding-left: 4px;
100+
visibility: hidden;
102101
}
103102

104103
.bigframes-widget th:hover .sort-indicator {
105-
visibility: visible;
104+
visibility: visible;
106105
}
107106

108107
.bigframes-widget button {
109-
cursor: pointer;
110-
display: inline-block;
111-
text-align: center;
112-
text-decoration: none;
113-
user-select: none;
114-
vertical-align: middle;
108+
cursor: pointer;
109+
display: inline-block;
110+
text-align: center;
111+
text-decoration: none;
112+
user-select: none;
113+
vertical-align: middle;
115114
}
116115

117116
.bigframes-widget button:disabled {
118-
opacity: 0.65;
119-
pointer-events: none;
117+
opacity: 0.65;
118+
pointer-events: none;
120119
}
121120

122121
.bigframes-widget .bigframes-error-message {
123-
background-color: #fbe;
124-
border: 1px solid red;
125-
border-radius: 4px;
126-
font-family:
127-
"-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", sans-serif;
128-
font-size: 14px;
129-
margin-bottom: 8px;
130-
padding: 8px;
122+
background-color: #fbe;
123+
border: 1px solid red;
124+
border-radius: 4px;
125+
font-family:
126+
"-apple-system", "BlinkMacSystemFont", "Segoe UI", "Roboto", sans-serif;
127+
font-size: 14px;
128+
margin-bottom: 8px;
129+
padding: 8px;
131130
}
132131

133132
.bigframes-widget .cell-align-right {
134-
text-align: right;
133+
text-align: right;
135134
}
136135

137136
.bigframes-widget .cell-align-left {
138-
text-align: left;
137+
text-align: left;
139138
}
140139

141140
.bigframes-widget .null-value {
142-
color: gray;
141+
color: gray;
143142
}
144143

145144
.bigframes-widget td {
146-
padding: 0.5em;
145+
padding: 0.5em;
147146
}
148147

149148
.bigframes-widget tr:hover td,
150149
.bigframes-widget td.row-hover {
151-
background-color: var(--colab-hover-surface-color, var(--jp-layout-color2));
150+
background-color: var(
151+
--colab-hover-surface-color,
152+
var(--jp-layout-color2, #f5f5f5)
153+
);
154+
}
155+
156+
@media (prefers-color-scheme: dark) {
157+
.bigframes-widget .footer,
158+
.bigframes-widget table {
159+
color: var(--colab-primary-text-color, var(--jp-ui-font-color0, white));
160+
}
161+
162+
.bigframes-widget th {
163+
background-color: var(
164+
--colab-primary-surface-color,
165+
var(--jp-layout-color0, #383838)
166+
);
167+
}
168+
169+
.bigframes-widget .bigframes-error-message {
170+
background-color: #511;
171+
border: 1px solid #f88;
172+
color: #fcc;
173+
}
174+
175+
.bigframes-widget .null-value {
176+
color: #aaa;
177+
}
178+
179+
.bigframes-widget tr:hover td,
180+
.bigframes-widget td.row-hover {
181+
background-color: var(
182+
--colab-hover-surface-color,
183+
var(--jp-layout-color2, #444)
184+
);
185+
}
152186
}

tests/unit/display/test_anywidget.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,21 @@ def handler(signum, frame):
7878
finally:
7979
if has_sigalrm:
8080
signal.alarm(0)
81+
82+
83+
def test_css_contains_dark_mode_media_query():
84+
from bigframes.display.anywidget import TableWidget
85+
86+
mock_df = mock.create_autospec(bigframes.dataframe.DataFrame, instance=True)
87+
# mock_df.columns and mock_df.dtypes are needed for __init__
88+
mock_df.columns = ["col1"]
89+
mock_df.dtypes = {"col1": "object"}
90+
91+
# Mock _block to avoid AttributeError during _set_table_html
92+
mock_block = mock.Mock()
93+
mock_block.has_index = False
94+
mock_df._block = mock_block
95+
96+
with mock.patch.object(TableWidget, "_initial_load"):
97+
widget = TableWidget(mock_df)
98+
assert "@media (prefers-color-scheme: dark)" in widget._css

0 commit comments

Comments
 (0)