Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions docs/design/tpr-ui-kit.html
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,7 @@
background: none;
border: none;
border-bottom: 2px solid transparent;
border-radius: 6px 6px 0 0;
margin-bottom: -1px;
padding: 10px 16px;
font-size: 14px;
Expand All @@ -1091,10 +1092,13 @@
.tablist button:hover {
color: var(--color-bluespruce);
border-bottom-color: var(--color-neutral-300);
background: var(--color-neutral-50);
}
.tablist button[aria-selected="true"] {
color: var(--color-bluespruce);
border-bottom-color: var(--color-bluespruce);
background: none;
font-weight: 600;
}
.tablist button.focus-demo {
box-shadow:
Expand Down Expand Up @@ -4065,13 +4069,15 @@ <h2>Tabs <span class="new-pill">v2</span></h2>
<h4>Tab list — selected / resting / keyboard focus</h4>
<p class="src">Tabs.tsx — Tabs + TabPanel + useActiveTab</p>
<div class="tags">
<span class="tag">px-4 py-2.5 text-sm font-medium</span
><span class="tag">border-b-2</span
<span class="tag">px-4 py-2.5 text-sm</span
><span class="tag">border-b-2 rounded-t-md cursor-pointer</span
><span class="tag"
>selected: border-bluespruce text-bluespruce</span
><span class="tag">resting: text-rmigray-600</span
>selected: font-semibold border-bluespruce
text-bluespruce</span
><span class="tag">resting: font-medium text-rmigray-600</span
><span class="tag"
>hover:text-bluespruce hover:border-neutral-300</span
>hover:text-bluespruce hover:border-neutral-300
hover:bg-neutral-50</span
><span class="tag">focus-visible:ring-energy</span>
</div>
</div>
Expand Down
9 changes: 9 additions & 0 deletions src/components/Tabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ describe("Tabs", () => {
expect(screen.getAllByRole("tab")).toHaveLength(3);
});

it("names each tab by its label alone", () => {
renderHarness();
// Each tab also holds a hidden copy of its label to reserve the semibold
// width; it must not be read out a second time ("One One").
for (const { label } of TABS) {
expect(screen.getByRole("tab", { name: label })).toBeInTheDocument();
}
});

it("defaults to the first tab and shows only its panel", () => {
renderHarness();
expect(screen.getByRole("tab", { name: "One" })).toHaveAttribute(
Expand Down
18 changes: 14 additions & 4 deletions src/components/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,13 +114,23 @@ export const Tabs: React.FC<TabsProps> = ({
tabIndex={selected ? 0 : -1}
onClick={() => onChange(t.id)}
className={clsx(
"px-4 py-2.5 text-sm font-medium border-b-2 transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-energy focus-visible:ring-offset-1",
"px-4 py-2.5 text-sm border-b-2 rounded-t-md cursor-pointer transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-energy focus-visible:ring-offset-1",
selected
? "border-bluespruce text-bluespruce"
: "border-transparent text-rmigray-600 hover:text-bluespruce hover:border-neutral-300",
? "font-semibold border-bluespruce text-bluespruce"
: "font-medium border-transparent text-rmigray-600 hover:text-bluespruce hover:border-neutral-300 hover:bg-neutral-50",
)}
>
{t.label}
<span className="inline-flex flex-col">
{t.label}
{/* Reserves the semibold width, so selecting a tab doesn't
nudge the tabs after it sideways. */}
<span
aria-hidden="true"
className="invisible h-0 overflow-hidden font-semibold"
>
{t.label}
</span>
</span>
</button>
);
})}
Expand Down
Loading