Skip to content

Commit 7f60d81

Browse files
authored
feat(Tabs)!: Add support for additional customization settings (#903)
* Add customization vars for hover/disabled states and shadow on selected tab * Add support for "full width" to the `<TabList>` component * Add support for "alignment" to the `<TabList>` component * Add support for animating tab selection * Fix import error * Add `exceptionallySetClassName` support to `<TabList>` component * Add storybook example for selected tab animation * review: Map the `align` to `justifyContent` with a variable for readability * review: Fix tab width/position when the viewport is resized * review: Add missing CSS properties to some classes * review: Add missing customization vars and use fill/tint naming * review: No need to repeat this property (already set on `.tab`) * review: Split tab border radius (for tab and track)
1 parent e4e9182 commit 7f60d81

File tree

3 files changed

+308
-32
lines changed

3 files changed

+308
-32
lines changed

src/tabs/tabs.module.css

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
:root {
2-
--reactist-tab-themed-background: var(--reactist-bg-default);
3-
--reactist-tab-themed-foreground: #006f85;
4-
--reactist-tab-themed-unselected: #006f85;
2+
--reactist-tab-themed-selected-tint: #006f85;
3+
--reactist-tab-themed-selected-fill: var(--reactist-bg-default);
4+
--reactist-tab-themed-unselected-tint: #006f85;
5+
--reactist-tab-themed-unselected-fill: transparent;
6+
--reactist-tab-themed-hover-tint: #006f85;
7+
--reactist-tab-themed-hover-fill: transparent;
8+
--reactist-tab-themed-disabled-tint: #006f85;
9+
--reactist-tab-themed-disabled-fill: transparent;
510
--reactist-tab-themed-track: rgb(242, 246, 247);
611
--reactist-tab-themed-border: var(--reactist-divider-secondary);
12+
--reactist-tab-themed-shadow: none;
713

8-
--reactist-tab-neutral-background: var(--reactist-bg-default);
9-
--reactist-tab-neutral-foreground: var(--reactist-content-primary);
10-
--reactist-tab-neutral-unselected: var(--reactist-content-tertiary);
14+
--reactist-tab-neutral-selected-tint: var(--reactist-content-primary);
15+
--reactist-tab-neutral-selected-fill: var(--reactist-bg-default);
16+
--reactist-tab-neutral-unselected-tint: var(--reactist-content-tertiary);
17+
--reactist-tab-neutral-unselected-fill: transparent;
18+
--reactist-tab-neutral-hover-tint: var(--reactist-content-tertiary);
19+
--reactist-tab-neutral-hover-fill: transparent;
20+
--reactist-tab-neutral-disabled-tint: var(--reactist-content-tertiary);
21+
--reactist-tab-neutral-disabled-fill: transparent;
1122
--reactist-tab-neutral-track: var(--reactist-framework-fill-selected);
1223
--reactist-tab-neutral-border: var(--reactist-divider-primary);
24+
--reactist-tab-neutral-shadow: none;
1325

26+
--reactist-tab-track-border-radius: 20px;
1427
--reactist-tab-track-border-width: 2px;
28+
--reactist-tab-selected-transition: none;
1529
--reactist-tab-border-radius: 20px;
1630
--reactist-tab-border-width: 1px;
1731
--reactist-tab-padding-x: var(--reactist-spacing-medium);
@@ -34,41 +48,76 @@
3448
border-radius: var(--reactist-tab-border-radius);
3549
}
3650

51+
.fullTabList .tab {
52+
flex: 1;
53+
}
54+
3755
.track {
3856
position: absolute;
3957
top: calc(-1 * var(--reactist-tab-track-border-width));
4058
right: calc(-1 * var(--reactist-tab-track-border-width));
4159
bottom: calc(-1 * var(--reactist-tab-track-border-width));
4260
left: calc(-1 * var(--reactist-tab-track-border-width));
43-
border-radius: var(--reactist-tab-border-radius);
61+
border-radius: var(--reactist-tab-track-border-radius);
4462
border-width: var(--reactist-tab-track-border-width);
4563
border-style: solid;
4664
}
4765

66+
.selected {
67+
position: absolute;
68+
z-index: 0;
69+
top: 0;
70+
height: 100%;
71+
border: var(--reactist-tab-border-width) solid transparent;
72+
border-radius: var(--reactist-tab-border-radius);
73+
transition: var(--reactist-tab-selected-transition);
74+
}
75+
4876
/*
4977
* Variant options
5078
*/
5179

5280
.tab,
5381
.tab-neutral {
54-
color: var(--reactist-tab-neutral-unselected);
82+
background-color: var(--reactist-tab-neutral-unselected-fill);
83+
color: var(--reactist-tab-neutral-unselected-tint);
5584
}
5685

5786
.tab[aria-selected='true'],
5887
.tab-neutral[aria-selected='true'] {
59-
background-color: var(--reactist-tab-neutral-background);
60-
color: var(--reactist-tab-neutral-foreground);
61-
border-color: var(--reactist-tab-neutral-border);
88+
color: var(--reactist-tab-neutral-selected-tint);
89+
}
90+
91+
.tab[aria-selected='false']:hover,
92+
.tab-neutral[aria-selected='false']:hover {
93+
background-color: var(--reactist-tab-neutral-hover-fill);
94+
color: var(--reactist-tab-neutral-hover-tint);
95+
}
96+
97+
.tab[aria-disabled='true'],
98+
.tab-neutral[aria-disabled='true'] {
99+
background-color: var(--reactist-tab-neutral-disabled-fill);
100+
color: var(--reactist-tab-neutral-disabled-tint);
101+
cursor: not-allowed;
62102
}
63103

64104
.tab-themed {
65-
color: var(--reactist-tab-themed-unselected);
105+
background-color: var(--reactist-tab-themed-unselected-fill);
106+
color: var(--reactist-tab-themed-unselected-tint);
66107
}
67108

68109
.tab-themed[aria-selected='true'] {
69-
background-color: var(--reactist-tab-themed-background);
70-
color: var(--reactist-tab-themed-foreground);
71-
border-color: var(--reactist-tab-themed-border);
110+
color: var(--reactist-tab-themed-selected-tint);
111+
}
112+
113+
.tab-themed[aria-selected='false']:hover {
114+
background-color: var(--reactist-tab-themed-hover-fill);
115+
color: var(--reactist-tab-themed-hover-tint);
116+
}
117+
118+
.tab-themed[aria-disabled='true'] {
119+
background-color: var(--reactist-tab-themed-disabled-fill);
120+
color: var(--reactist-tab-themed-disabled-tint);
72121
}
73122

74123
.track,
@@ -81,3 +130,16 @@
81130
background: var(--reactist-tab-themed-track);
82131
border-color: var(--reactist-tab-themed-track);
83132
}
133+
134+
.selected,
135+
.selected-neutral {
136+
background-color: var(--reactist-tab-neutral-selected-fill);
137+
border-color: var(--reactist-tab-neutral-border);
138+
box-shadow: var(--reactist-tab-neutral-shadow);
139+
}
140+
141+
.selected-themed {
142+
background-color: var(--reactist-tab-themed-selected-fill);
143+
border-color: var(--reactist-tab-themed-border);
144+
box-shadow: var(--reactist-tab-themed-shadow);
145+
}

src/tabs/tabs.stories.mdx

Lines changed: 128 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,22 +127,35 @@ export const Template = ({
127127
The following CSS custom properties are available so that the tabs' colors can be customized:
128128

129129
```
130-
--reactist-tab-neutral-background
131-
--reactist-tab-neutral-foreground
132-
--reactist-tab-neutral-unselected
130+
--reactist-tab-neutral-selected-tint
131+
--reactist-tab-neutral-selected-fill
132+
--reactist-tab-neutral-unselected-tint
133+
--reactist-tab-neutral-unselected-fill
134+
--reactist-tab-neutral-hover-tint
135+
--reactist-tab-neutral-hover-fill
136+
--reactist-tab-neutral-disabled-tint
137+
--reactist-tab-neutral-disabled-fill
133138
--reactist-tab-neutral-track
134139
--reactist-tab-neutral-border
135140
136-
--reactist-tab-themed-background
137-
--reactist-tab-themed-foreground
138-
--reactist-tab-themed-unselected
141+
--reactist-tab-themed-selected-tint
142+
--reactist-tab-themed-selected-fill
143+
--reactist-tab-themed-unselected-tint
144+
--reactist-tab-themed-unselected-fill
145+
--reactist-tab-themed-hover-tint
146+
--reactist-tab-themed-hover-fill
147+
--reactist-tab-themed-disabled-tint
148+
--reactist-tab-themed-disabled-fill
139149
--reactist-tab-themed-track
140150
--reactist-tab-themed-border
141151
```
142152

143-
Their size can also be customized with:
153+
## Sizes
154+
155+
The following CSS custom properties are available so that the tabs' sizes can be customized:
144156

145157
```
158+
--reactist-tab-track-border-radius
146159
--reactist-tab-track-border-width
147160
--reactist-tab-border-radius
148161
--reactist-tab-border-width
@@ -151,6 +164,18 @@ Their size can also be customized with:
151164
--reactist-tab-line-height
152165
```
153166

167+
## Other
168+
169+
The following CSS custom properties are also available to customize other tabs' styles:
170+
171+
```
172+
--reactist-tab-neutral-shadow
173+
174+
--reactist-tab-themed-shadow
175+
176+
--reactist-tab-selected-transition
177+
```
178+
154179
## Stories
155180

156181
### Themed variant
@@ -168,6 +193,102 @@ Their size can also be customized with:
168193
</Story>
169194
</Canvas>
170195

196+
### Full container width tabs
197+
198+
<Canvas withToolbar>
199+
<Story parameters={{ docs: { source: { type: 'code' } } }} name="Full container width tabs">
200+
<Tabs>
201+
<TabList aria-label="Full width tabs example" width="full">
202+
<Tab id="tab1">Tab 1</Tab>
203+
<Tab id="tab2">Tab 2</Tab>
204+
<Tab id="tab3">Tab 3</Tab>
205+
</TabList>
206+
<TabPanel id="tab1">
207+
<Box paddingX="small" paddingY="xlarge">
208+
<Text>Content of tab 1</Text>
209+
</Box>
210+
</TabPanel>
211+
<TabPanel id="tab2">
212+
<Box paddingX="small" paddingY="xlarge">
213+
<Text>Content of tab 2</Text>
214+
</Box>
215+
</TabPanel>
216+
<TabPanel id="tab3">
217+
<Box paddingX="small" paddingY="xlarge">
218+
<Text>Content of tab 3</Text>
219+
</Box>
220+
</TabPanel>
221+
</Tabs>
222+
</Story>
223+
</Canvas>
224+
225+
### Tabs aligned to the center
226+
227+
<Canvas withToolbar>
228+
<Story parameters={{ docs: { source: { type: 'code' } } }} name="Tabs aligned to the center">
229+
<Tabs>
230+
<TabList aria-label="Full width tabs example" align="center">
231+
<Tab id="tab1">Tab 1</Tab>
232+
<Tab id="tab2">Tab 2</Tab>
233+
<Tab id="tab3">Tab 3</Tab>
234+
</TabList>
235+
<TabPanel id="tab1">
236+
<Box paddingX="small" paddingY="xlarge">
237+
<Text>Content of tab 1</Text>
238+
</Box>
239+
</TabPanel>
240+
<TabPanel id="tab2">
241+
<Box paddingX="small" paddingY="xlarge">
242+
<Text>Content of tab 2</Text>
243+
</Box>
244+
</TabPanel>
245+
<TabPanel id="tab3">
246+
<Box paddingX="small" paddingY="xlarge">
247+
<Text>Content of tab 3</Text>
248+
</Box>
249+
</TabPanel>
250+
</Tabs>
251+
</Story>
252+
</Canvas>
253+
254+
### Selected tab with slide animation
255+
256+
<Canvas withToolbar>
257+
<Story
258+
parameters={{ docs: { source: { type: 'code' } } }}
259+
name="Selected tab with slide animation"
260+
style={{ border: '1px solid red' }}
261+
>
262+
<Tabs>
263+
<style>
264+
{
265+
'.transition { --reactist-tab-selected-transition: left 0.3s ease, width 0.3s ease; }'
266+
}
267+
</style>
268+
<TabList aria-label="Full width tabs example" exceptionallySetClassName="transition">
269+
<Tab id="tab1">Tab 1</Tab>
270+
<Tab id="tab2">Tab 2</Tab>
271+
<Tab id="tab3">Tab 3</Tab>
272+
</TabList>
273+
<TabPanel id="tab1">
274+
<Box paddingX="small" paddingY="xlarge">
275+
<Text>Content of tab 1</Text>
276+
</Box>
277+
</TabPanel>
278+
<TabPanel id="tab2">
279+
<Box paddingX="small" paddingY="xlarge">
280+
<Text>Content of tab 2</Text>
281+
</Box>
282+
</TabPanel>
283+
<TabPanel id="tab3">
284+
<Box paddingX="small" paddingY="xlarge">
285+
<Text>Content of tab 3</Text>
286+
</Box>
287+
</TabPanel>
288+
</Tabs>
289+
</Story>
290+
</Canvas>
291+
171292
### Using the `<TabAwareSlot>` component
172293

173294
<Canvas withToolbar>

0 commit comments

Comments
 (0)