Skip to content

Commit

Permalink
fix: TabsTrigger tabindex
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte committed Nov 19, 2024
1 parent a7be55b commit 32625fd
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/real-berries-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": patch
---

fix: `TabTrigger` default tabindex handling
37 changes: 14 additions & 23 deletions packages/bits-ui/src/lib/bits/tabs/tabs.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { untrack } from "svelte";
import { SvelteMap } from "svelte/reactivity";
import { useRefById } from "svelte-toolbelt";
import type { FocusEventHandler, KeyboardEventHandler, MouseEventHandler } from "svelte/elements";
import type { TabsActivationMode } from "./types.js";
import {
getAriaOrientation,
Expand Down Expand Up @@ -192,8 +193,11 @@ class TabsTriggerState {
});

$effect(() => {
if (this.#root.triggerIds.length) {
this.#tabIndex = this.#root.rovingFocusGroup.getTabIndex(this.#ref.current);
this.#root.triggerIds.length;
if (this.#isActive || !this.#root.value.current) {
this.#tabIndex = 0;
} else {
this.#tabIndex = -1;
}
});
}
Expand All @@ -203,29 +207,17 @@ class TabsTriggerState {
this.#root.setValue(this.#value.current);
};

#onfocus = () => {
if (this.#root.activationMode.current !== "automatic" || this.#disabled.current) return;
#onfocus: FocusEventHandler<HTMLButtonElement> = () => {
if (this.#root.activationMode.current !== "automatic" || this.#isDisabled) return;
this.activate();
};

#onpointerdown = (e: PointerEvent) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch" || e.button !== 0) return e.preventDefault();
e.preventDefault();
this.#ref.current?.focus();
#onclick: MouseEventHandler<HTMLButtonElement> = (e) => {
if (this.#isDisabled) return;
this.activate();
};

#onpointerup = (e: PointerEvent) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch") {
e.preventDefault();
this.#ref.current?.focus();
this.activate();
}
};

#onkeydown = (e: KeyboardEvent) => {
#onkeydown: KeyboardEventHandler<HTMLButtonElement> = (e) => {
if (this.#isDisabled) return;
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
e.preventDefault();
Expand All @@ -243,15 +235,14 @@ class TabsTriggerState {
"data-state": getTabDataState(this.#isActive),
"data-value": this.#value.current,
"data-orientation": getDataOrientation(this.#root.orientation.current),
"data-disabled": getDataDisabled(this.#disabled.current),
"data-disabled": getDataDisabled(this.#isDisabled),
"aria-selected": getAriaSelected(this.#isActive),
"aria-controls": this.#ariaControls,
[TRIGGER_ATTR]: "",
disabled: getDisabled(this.#disabled.current),
disabled: getDisabled(this.#isDisabled),
tabindex: this.#tabIndex,
//
onpointerdown: this.#onpointerdown,
onpointerup: this.#onpointerup,
onclick: this.#onclick,
onfocus: this.#onfocus,
onkeydown: this.#onkeydown,
}) as const
Expand Down
15 changes: 15 additions & 0 deletions packages/tests/src/tests/tabs/tabs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,4 +246,19 @@ describe("tabs", () => {
expect(content.getAttribute("aria-labelledby")).toBe(trigger.id);
}
});

it("should apply tabindex 0 to the active tab trigger on mount", async () => {
const { getByTestId } = setup({
value: "2",
});
const [trigger1, trigger2, trigger3] = [
getByTestId("trigger-1"),
getByTestId("trigger-2"),
getByTestId("trigger-3"),
];

expect(trigger1).toHaveAttribute("tabindex", "-1");
expect(trigger2).toHaveAttribute("tabindex", "0");
expect(trigger3).toHaveAttribute("tabindex", "-1");
});
});

0 comments on commit 32625fd

Please sign in to comment.