fix: make settings sidebar accordion items keyboard accessible (#20663)

* fix: make settings sidebar accordion items keyboard accessible

Co-Authored-By: sean@cal.com <sean@cal.com>

* fix: ensure keyboard events properly toggle accordion content

Co-Authored-By: sean@cal.com <sean@cal.com>

* fix: add toggle functionality to accordion buttons

Co-Authored-By: sean@cal.com <sean@cal.com>

* fix: clean up accordion code and improve keyboard accessibility

Co-Authored-By: sean@cal.com <sean@cal.com>

* fix: add keyboard event handlers for accordion toggle

Co-Authored-By: sean@cal.com <sean@cal.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: sean@cal.com <sean@cal.com>
This commit is contained in:
devin-ai-integration[bot]
2025-04-14 08:55:13 +00:00
committed by GitHub
co-authored by sean@cal.com <sean@cal.com> sean@cal.com <sean@cal.com> sean@cal.com <sean@cal.com> sean@cal.com <sean@cal.com> sean@cal.com <sean@cal.com> Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> sean@cal.com <sean@cal.com>
parent ad4aeee45b
commit 65abf4edc6
@@ -314,27 +314,41 @@ const TeamListCollapsible = () => {
className="cursor-pointer"
key={team.id}
open={teamMenuState[index].teamMenuOpen}
onOpenChange={() =>
setTeamMenuState([
...teamMenuState,
(teamMenuState[index] = {
...teamMenuState[index],
teamMenuOpen: !teamMenuState[index].teamMenuOpen,
}),
])
}>
onOpenChange={(open) => {
const newTeamMenuState = [...teamMenuState];
newTeamMenuState[index] = {
...newTeamMenuState[index],
teamMenuOpen: open,
};
setTeamMenuState(newTeamMenuState);
}}>
<CollapsibleTrigger asChild>
<div
<button
className="hover:bg-subtle [&[aria-current='page']]:bg-emphasis [&[aria-current='page']]:text-emphasis text-default flex h-9 w-full flex-row items-center rounded-md px-2 py-[10px] text-left text-sm font-medium leading-none transition"
onClick={() =>
setTeamMenuState([
...teamMenuState,
(teamMenuState[index] = {
...teamMenuState[index],
aria-controls={`team-content-${team.id}`}
aria-expanded={teamMenuState[index].teamMenuOpen}
onClick={() => {
const newTeamMenuState = [...teamMenuState];
newTeamMenuState[index] = {
...newTeamMenuState[index],
teamMenuOpen: !teamMenuState[index].teamMenuOpen,
};
setTeamMenuState(newTeamMenuState);
}}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
const newTeamMenuState = [...teamMenuState];
newTeamMenuState[index] = {
...newTeamMenuState[index],
teamMenuOpen: !teamMenuState[index].teamMenuOpen,
}),
])
}>
};
setTeamMenuState(newTeamMenuState);
}
}}
aria-label={`${team.name} ${
teamMenuState[index].teamMenuOpen ? t("collapse_menu") : t("expand_menu")
}`}>
<div className="me-3">
{teamMenuState[index].teamMenuOpen ? (
<Icon name="chevron-down" className="h-4 w-4" />
@@ -355,9 +369,9 @@ const TeamListCollapsible = () => {
Inv.
</Badge>
)}
</div>
</button>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-0.5">
<CollapsibleContent className="space-y-0.5" id={`team-content-${team.id}`}>
{team.accepted && (
<VerticalTabItem
name={t("profile")}
@@ -484,7 +498,7 @@ const SettingsSidebarContainer = ({
? "translate-x-0 opacity-100"
: "-translate-x-full opacity-0 lg:translate-x-0 lg:opacity-100"
)}
aria-label="Tabs">
aria-label={t("settings_navigation")}>
<>
<BackButtonInSidebar name={t("back")} />
{tabsWithPermissions.map((tab) => {
@@ -600,27 +614,43 @@ const SettingsSidebarContainer = ({
className="cursor-pointer"
key={otherTeam.id}
open={otherTeamMenuState[index].teamMenuOpen}
onOpenChange={() =>
setOtherTeamMenuState([
...otherTeamMenuState,
(otherTeamMenuState[index] = {
...otherTeamMenuState[index],
teamMenuOpen: !otherTeamMenuState[index].teamMenuOpen,
}),
])
}>
onOpenChange={(open) => {
const newOtherTeamMenuState = [...otherTeamMenuState];
newOtherTeamMenuState[index] = {
...newOtherTeamMenuState[index],
teamMenuOpen: open,
};
setOtherTeamMenuState(newOtherTeamMenuState);
}}>
<CollapsibleTrigger asChild>
<div
<button
className="hover:bg-subtle [&[aria-current='page']]:bg-emphasis [&[aria-current='page']]:text-emphasis text-default flex h-9 w-full flex-row items-center rounded-md px-2 py-[10px] text-left text-sm font-medium leading-none transition"
onClick={() =>
setOtherTeamMenuState([
...otherTeamMenuState,
(otherTeamMenuState[index] = {
...otherTeamMenuState[index],
aria-controls={`other-team-content-${otherTeam.id}`}
aria-expanded={otherTeamMenuState[index].teamMenuOpen}
onClick={() => {
const newOtherTeamMenuState = [...otherTeamMenuState];
newOtherTeamMenuState[index] = {
...newOtherTeamMenuState[index],
teamMenuOpen: !otherTeamMenuState[index].teamMenuOpen,
};
setOtherTeamMenuState(newOtherTeamMenuState);
}}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
const newOtherTeamMenuState = [...otherTeamMenuState];
newOtherTeamMenuState[index] = {
...newOtherTeamMenuState[index],
teamMenuOpen: !otherTeamMenuState[index].teamMenuOpen,
}),
])
}>
};
setOtherTeamMenuState(newOtherTeamMenuState);
}
}}
aria-label={`${otherTeam.name} ${
otherTeamMenuState[index].teamMenuOpen
? t("collapse_menu")
: t("expand_menu")
}`}>
<div className="me-3">
{otherTeamMenuState[index].teamMenuOpen ? (
<Icon name="chevron-down" className="h-4 w-4" />
@@ -636,9 +666,11 @@ const SettingsSidebarContainer = ({
/>
)}
<p className="w-1/2 truncate leading-normal">{otherTeam.name}</p>
</div>
</button>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-0.5">
<CollapsibleContent
className="space-y-0.5"
id={`other-team-content-${otherTeam.id}`}>
<VerticalTabItem
name={t("profile")}
href={`/settings/organizations/teams/other/${otherTeam.id}/profile`}