diff --git a/apps/website/pages/components/nav-tabs/code.tsx b/apps/website/pages/components/nav-tabs/code.tsx
index b6e2985afa..8a24f391f7 100644
--- a/apps/website/pages/components/nav-tabs/code.tsx
+++ b/apps/website/pages/components/nav-tabs/code.tsx
@@ -6,7 +6,7 @@ import NavTabsCodePage from "screens/components/nav-tabs/code/NavTabsCodePage";
const Code = () => (
<>
- Nav Tabs Code — Halstack Design System
+ Nav tabs code — Halstack Design System
>
diff --git a/apps/website/pages/components/nav-tabs/index.tsx b/apps/website/pages/components/nav-tabs/index.tsx
index d7d3c23176..8bd45d9056 100644
--- a/apps/website/pages/components/nav-tabs/index.tsx
+++ b/apps/website/pages/components/nav-tabs/index.tsx
@@ -6,7 +6,7 @@ import NavTabsOverviewPage from "screens/components/nav-tabs/overview/NavTabsOve
const Index = () => (
<>
- Nav Tabs — Halstack Design System
+ Nav tabs — Halstack Design System
>
diff --git a/apps/website/screens/components/nav-tabs/NavTabsPageLayout.tsx b/apps/website/screens/components/nav-tabs/NavTabsPageLayout.tsx
index 16077c5cd3..6cd8ccf9e3 100644
--- a/apps/website/screens/components/nav-tabs/NavTabsPageLayout.tsx
+++ b/apps/website/screens/components/nav-tabs/NavTabsPageLayout.tsx
@@ -14,12 +14,12 @@ const NumberInputPageHeading = ({ children }: { children: ReactNode }) => {
-
+
Nav tabs lets users switch between different views or sections within the same page, organizing related
content into a clear and accessible layout.
-
+
{children}
diff --git a/apps/website/screens/components/nav-tabs/code/NavTabsCodePage.tsx b/apps/website/screens/components/nav-tabs/code/NavTabsCodePage.tsx
index 20157e8204..f91c870af7 100644
--- a/apps/website/screens/components/nav-tabs/code/NavTabsCodePage.tsx
+++ b/apps/website/screens/components/nav-tabs/code/NavTabsCodePage.tsx
@@ -44,11 +44,11 @@ const sections = [
| iconPosition |
- 'top' | 'left'
+ 'left' | 'top'
|
Whether the icon should appear above or to the left of the label. |
- 'top'
+ 'left'
|
@@ -263,15 +263,13 @@ const sections = [
},
];
-const NavTabsCodePage = () => {
- return (
-
-
-
-
-
-
- );
-};
+const NavTabsCodePage = () => (
+
+
+
+
+
+
+);
export default NavTabsCodePage;
diff --git a/apps/website/screens/components/nav-tabs/overview/NavTabsOverviewPage.tsx b/apps/website/screens/components/nav-tabs/overview/NavTabsOverviewPage.tsx
index 768921134f..73f4becbff 100644
--- a/apps/website/screens/components/nav-tabs/overview/NavTabsOverviewPage.tsx
+++ b/apps/website/screens/components/nav-tabs/overview/NavTabsOverviewPage.tsx
@@ -30,32 +30,30 @@ const sections = [
- Container: the outer wrapper that holds and organizes all tab items. It defines the overall
+ Container: the outer wrapper that holds and organizes all tab items. It defines the overall
structure and layout of the navigation tabs, ensuring proper alignment and spacing across the component.
- Label: the text displayed within each tab that indicates the section or category it leads
+ Label: the text displayed within each tab that indicates the section or category it leads
to.
- Notification badge
- (Optional): a visual indicator that displays the number of pending actions, alerts or updates
- related to a specific tab.
+ Notification badge (Optional): a visual indicator that displays the number of
+ pending actions, alerts or updates related to a specific tab.
- Selected tab: the active tab currently in focus, representing the visible content section.
+ Selected tab: the active tab currently in focus, representing the visible content section.
It is visually distinguished from unselected tabs using different color, weight or indicator styling.
- Icon
- (Optional): an optional graphical element placed before the label to visually reinforce the tab's
- meaning or category.
+ Icon (Optional): an optional graphical element placed before the label to visually
+ reinforce the tab's meaning or category.
- Selected tab indicator: a horizontal bar that visually marks the currently active tab.
+ Selected tab indicator: a horizontal bar that visually marks the currently active tab.
- Unselected tab indicator: a horizontal bar that visually marks the currently inactive tab.
+ Unselected tab indicator: a horizontal bar that visually marks the currently inactive tab.
>
@@ -75,7 +73,7 @@ const sections = [
Use the top position when the tabs are displayed in a horizontal layout and you want to
- emphasize the icon as a key visual cue—ideal for dashboards or mobile - first interfaces where vertical
+ emphasize the icon as a key visual cue—ideal for dashboards or mobile-first interfaces where vertical
stacking feels more natural.
@@ -140,8 +138,8 @@ const sections = [
Both components improve usability, but tabs are best for grouping related content within
- a page, while
- nav tabs help users move across different sections or pages of an application.
+ a page, while nav tabs help users move across different sections or pages of an
+ application.
>
),
@@ -162,17 +160,22 @@ const sections = [
especially on smaller viewports.
- Ensure that tabs follow a logical order — based on frequency of use, workflow, or user
+ Ensure that tabs follow a logical order—based on frequency of use, workflow, or user
priority.
Use notification badges to highlight relevant updates only when necessary, and avoid
overloading multiple tabs with badges at once.
+
+ While the component is flexible enough to support a mix of label-only and label-with-icon tabs, it's best to
+ choose one style per set. Mixing both can reduce scannability and create visual imbalance, impacting the
+ overall usability.
+
Choose icon placement (left or top) based on the available space and the importance of the icon in the
- context of the label. Left is preferred for horizontal layouts; top works best in vertical or space -
- constrained scenarios.
+ context of the label. Left is preferred for horizontal layouts; top works best in vertical or
+ space-constrained scenarios.
Avoid mixing navigation tabs and action buttons within the same group, as this can create confusion around
@@ -184,15 +187,13 @@ const sections = [
},
];
-const NavTabsOverviewPage = () => {
- return (
-
-
-
-
-
-
- );
-};
+const NavTabsOverviewPage = () => (
+
+
+
+
+
+
+);
export default NavTabsOverviewPage;
diff --git a/apps/website/screens/components/tabs/overview/TabsOverviewPage.tsx b/apps/website/screens/components/tabs/overview/TabsOverviewPage.tsx
index 6c71061f54..6963a02848 100644
--- a/apps/website/screens/components/tabs/overview/TabsOverviewPage.tsx
+++ b/apps/website/screens/components/tabs/overview/TabsOverviewPage.tsx
@@ -160,72 +160,37 @@ const sections = [
{
title: "Best practices",
content: (
-
- To ensure an intuitive and user-friendly experience, follow these best practices when designing and implementing
- tabs:
-
+
+
+ Maintain logical order: arrange tabs in a meaningful sequence based on user needs and place
+ frequently used or primary tabs first.
+
+
+ Keep tab labels short & clear: use concise, descriptive labels (1-2 words) that clearly
+ indicate the content. Avoid using generic or ambiguous labels like "Info" or "More." Instead, choose specific
+ terms that reflect the content, such as "Account Details" for user-related settings or "Billing" for payment
+ information and prioritize readability—avoid using all caps unless necessary.
+
+
+ Managing the number of tabs effectively: while not a strict rule, keeping the number of tabs
+ manageable (ideally 5-7) helps maintain clarity and usability. If additional tabs are necessary, assess the
+ information architecture carefully and consider grouping related items.
+
+
+ Use icons thoughtfully: ensure the icon is intuitive and clearly represents the content of
+ the tab. While they are generally used alongside labels, they can also be used independently. In such cases,
+ it is crucial to choose highly recognizable icons that clearly convey meaning without additional text. When
+ used together, the icon and label must work harmoniously to reinforce their meaning and avoid any conflicting
+ interpretations. Avoid using overly decorative or generic icons that do not provide clear meaning, such as an
+ abstract shape with no context.
+
+
+ Keep design consistent: while the component is flexible enough to support a mix of label-only
+ and label-with-icon tabs, it's best to choose one style per set. Mixing both can reduce scannability and
+ create visual imbalance, impacting the overall usability.
+
+
),
- subSections: [
- {
- title: "Maintain logical order",
- content: (
-
- Arrange tabs in a meaningful sequence based on user needs.
- Place frequently used or primary tabs first.
-
- ),
- },
- {
- title: "Keep tab labels short & clear",
- content: (
-
-
- Use concise, descriptive labels (1-2 words) that clearly indicate the content.
-
-
- Avoid using generic or ambiguous labels like "Info" or "More." Instead, choose specific terms that reflect
- the content, such as "Account Details" for user-related settings or "Billing" for payment information.
-
- Prioritize readability—avoid using all caps unless necessary.
-
- ),
- },
- {
- title: "Managing the number of tabs effectively",
- content: (
-
-
- While not a strict rule, keeping the number of tabs manageable (ideally 5-7) helps maintain clarity and
- usability.
-
-
- If additional tabs are necessary, assess the information architecture carefully and consider grouping
- related items.
-
-
- ),
- },
- {
- title: "Use icons thoughtfully",
- content: (
-
-
- Ensure the icon is intuitive and clearly represents the content of the tab. While they are generally used
- alongside labels, they can also be used independently. In such cases, it is crucial to choose highly
- recognizable icons that clearly convey meaning without additional text.
-
-
- When used together, the icon and label must work harmoniously to reinforce their meaning and avoid any
- conflicting interpretations.
-
-
- Avoid using overly decorative or generic icons that do not provide clear meaning, such as an abstract
- shape with no context.
-
-
- ),
- },
- ],
},
];
diff --git a/packages/lib/src/divider/Divider.tsx b/packages/lib/src/divider/Divider.tsx
index c0e328d1f3..40fe221723 100644
--- a/packages/lib/src/divider/Divider.tsx
+++ b/packages/lib/src/divider/Divider.tsx
@@ -11,29 +11,29 @@ const StyledDivider = styled.hr`
: "var(--border-color-neutral-strongest)"
};
${orientation === "horizontal" ? "width" : "min-height"}: 100%;
- ${orientation === "horizontal" ? "height" : "width"}: 0px;
+ ${orientation === "horizontal" ? "height" : "width"}: 0;
${
orientation === "horizontal"
- ? "border-width: " + (weight === "regular" ? "1px 0 0 0" : "2px 0 0 0")
- : "border-width: " + (weight === "regular" ? "0 0 0 1px" : "0 0 0 2px")
+ ? "border-width: " + (weight === "regular" ? "var(--border-width-s) 0 0 0" : "var(--border-width-m) 0 0 0")
+ : "border-width: " + (weight === "regular" ? "0 0 0 var(--border-width-s)" : "0 0 0 var(--border-width-m)")
};
- margin: 0px;
+ margin: 0;
`}
`;
-const DxcDivider = ({
- orientation = "horizontal",
- weight = "regular",
+export default function DxcDivider({
color = "mediumGrey",
decorative = true,
-}: DividerPropsType) => (
-
-);
-
-export default DxcDivider;
+ orientation = "horizontal",
+ weight = "regular",
+}: DividerPropsType) {
+ return (
+
+ );
+}
diff --git a/packages/lib/src/nav-tabs/NavTabs.stories.tsx b/packages/lib/src/nav-tabs/NavTabs.stories.tsx
index 77bd08ac54..96c0401d08 100644
--- a/packages/lib/src/nav-tabs/NavTabs.stories.tsx
+++ b/packages/lib/src/nav-tabs/NavTabs.stories.tsx
@@ -1,3 +1,4 @@
+import { INITIAL_VIEWPORTS } from "@storybook/addon-viewport";
import { Meta, StoryObj } from "@storybook/react";
import ExampleContainer from "../../.storybook/components/ExampleContainer";
import Title from "../../.storybook/components/Title";
@@ -7,6 +8,11 @@ import DxcNavTabs from "./NavTabs";
export default {
title: "Nav Tabs",
component: DxcNavTabs,
+ parameters: {
+ viewport: {
+ viewports: INITIAL_VIEWPORTS,
+ },
+ },
} as Meta;
const iconSVG = (
@@ -16,10 +22,6 @@ const iconSVG = (
);
-const favoriteIcon = "filled_Favorite";
-
-const pinIcon = "Location_On";
-
const NavTabs = () => (
<>
@@ -93,103 +95,102 @@ const NavTabs = () => (
-
+
Tab 1
Tab 2
-
+
Tab 3
-
+
Tab 4
-
-
+
+
Tab 1
-
+
Tab 2
-
+
Tab 3
-
+
Tab 4
-
-
-
+
+
+
Tab 1
-
+
Tab 2
-
+
Tab 3
-
+
Tab 4
-
-
-
+
+
+
Tab 1
-
+
Tab 2
-
+
Tab 3
-
+
Tab 4
-
-
+
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit
-
+
Tab 2
-
+
Tab 3
-
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit
-
+
Tab 2
-
+
Tab 3
-
-
+
@@ -206,8 +207,40 @@ const NavTabs = () => (
>
);
+const Scroll = () => (
+ <>
+
+
+
+
+ Tab 1
+
+
+ Tab 2
+
+
+ Tab 3
+
+
+ Tab 4
+
+
+
+ >
+);
+
type Story = StoryObj;
export const Chromatic: Story = {
render: NavTabs,
};
+
+export const ScrollableNavTabs: Story = {
+ render: Scroll,
+ parameters: {
+ viewport: {
+ defaultViewport: "iphonex",
+ },
+ chromatic: { viewports: [375], delay: 5000 },
+ },
+};
diff --git a/packages/lib/src/nav-tabs/NavTabs.tsx b/packages/lib/src/nav-tabs/NavTabs.tsx
index e9cf9d1b64..880508f94e 100644
--- a/packages/lib/src/nav-tabs/NavTabs.tsx
+++ b/packages/lib/src/nav-tabs/NavTabs.tsx
@@ -1,79 +1,32 @@
-import { Children, KeyboardEvent, ReactElement, ReactNode, useEffect, useMemo, useRef, useState } from "react";
+import { Children, KeyboardEvent, ReactElement, useMemo, useState } from "react";
import styled from "styled-components";
import NavTabsPropsType from "./types";
-import DxcTab from "./Tab";
+import Tab from "./Tab";
import NavTabsContext from "./NavTabsContext";
+import { getLabelFromTab, getPropInChild, getPreviousTabIndex, getNextTabIndex } from "./utils";
-const getPropInChild = (child: ReactNode, propName: string) => {
- if (child && typeof child === "object" && "props" in child) {
- const childWithProps = child as ReactElement;
- if (childWithProps.props[propName]) {
- return childWithProps.props[propName];
- } else if (childWithProps.props.children) {
- return getPropInChild(childWithProps.props.children, propName);
- }
- }
-};
-
-const getLabelFromTab = (child: ReactNode) => {
- if (typeof child === "string") {
- return child;
- } else if (child && typeof child === "object" && "props" in child) {
- const childWithProps = child as ReactElement;
- if (Array.isArray(childWithProps.props.children)) {
- return getLabelFromTab(childWithProps.props.children[0]);
- } else {
- return getLabelFromTab(childWithProps.props.children);
- }
- }
-};
-
-const getPreviousTabIndex = (array: ReactElement[], initialIndex: number): number => {
- let index = initialIndex === 0 ? array.length - 1 : initialIndex - 1;
- while (getPropInChild(array[index], "disabled")) {
- index = index === 0 ? array.length - 1 : index - 1;
- }
- return index;
-};
-
-const getNextTabIndex = (array: ReactElement[], initialIndex: number): number => {
- let index = initialIndex === array.length - 1 ? 0 : initialIndex + 1;
- while (getPropInChild(array[index], "disabled")) {
- index = index === array.length - 1 ? 0 : index + 1;
- }
- return index;
-};
+const NavTabsContainer = styled.div`
+ position: relative;
+ display: flex;
+ overflow: auto hidden;
+`;
-const Underline = styled.div<{ underlineWidth: number }>`
+const Underline = styled.div`
position: absolute;
bottom: 0;
left: 0;
height: var(--border-width-m);
background-color: var(--border-color-neutral-medium);
- z-index: -1;
- width: ${(props) => props.underlineWidth}px;
+ width: 100%;
`;
-const NavTabsContainer = styled.div`
- display: flex;
- position: relative;
- overflow: auto;
- z-index: 0;
-`;
-
-const DxcNavTabs = ({ iconPosition = "top", tabIndex = 0, children }: NavTabsPropsType): JSX.Element => {
+const DxcNavTabs = ({ iconPosition = "left", tabIndex = 0, children }: NavTabsPropsType): JSX.Element => {
const [innerFocusIndex, setInnerFocusIndex] = useState(null);
- const [underlineWidth, setUnderlineWidth] = useState(null);
- const refNavTabList = useRef(null);
const childArray = Children.toArray(children).filter(
(child) => typeof child === "object" && "props" in child
) as ReactElement[];
- useEffect(() => {
- setUnderlineWidth(refNavTabList?.current?.scrollWidth ?? null);
- }, [children]);
-
const contextValue = useMemo(
() => ({
iconPosition,
@@ -103,13 +56,13 @@ const DxcNavTabs = ({ iconPosition = "top", tabIndex = 0, children }: NavTabsPro
};
return (
-
+
+
{children}
-
);
};
-DxcNavTabs.Tab = DxcTab;
+DxcNavTabs.Tab = Tab;
export default DxcNavTabs;
diff --git a/packages/lib/src/nav-tabs/Tab.tsx b/packages/lib/src/nav-tabs/Tab.tsx
index 5aec52514b..fda9312a8a 100644
--- a/packages/lib/src/nav-tabs/Tab.tsx
+++ b/packages/lib/src/nav-tabs/Tab.tsx
@@ -5,57 +5,54 @@ import DxcFlex from "../flex/Flex";
import NavTabsPropsType, { TabProps } from "./types";
import NavTabsContext from "./NavTabsContext";
import DxcIcon from "../icon/Icon";
+import DxcInset from "../inset/Inset";
-const TabContainer = styled.div<{ active: TabProps["active"] }>`
- align-items: stretch;
- border-bottom: var(--border-width-s) var(--border-style-default)
- ${(props) => (props.active ? "var(--border-color-primary-stronger)" : "transparent")};
- padding: var(--spacing-padding-xs);
+const TabContainer = styled.div`
+ position: relative;
+ display: flex;
+ flex-direction: column;
`;
-const Tab = styled.a<{
+const TabLink = styled.a<{
disabled: TabProps["disabled"];
- hasIcon: boolean;
iconPosition: NavTabsPropsType["iconPosition"];
}>`
box-sizing: border-box;
display: flex;
- flex-direction: ${(props) => (props.hasIcon && props.iconPosition === "top" ? "column" : "row")};
+ flex-direction: ${({ iconPosition }) => (iconPosition === "top" ? "column" : "row")};
justify-content: center;
align-items: center;
gap: var(--spacing-gap-xs);
- height: ${(props) => (props.hasIcon && props.iconPosition === "top" ? "78px" : "100%")};
+ height: ${({ iconPosition }) => (iconPosition === "top" ? "78px" : "100%")};
min-width: 176px;
min-height: 48px;
padding: var(--spacing-padding-none) var(--spacing-padding-xs);
border-radius: var(--border-radius-s);
- background: var(--color-bg-neutral-lightest);
- text-decoration-color: transparent;
- text-decoration-line: none;
- cursor: ${(props) => (props.disabled ? "not-allowed" : "pointer")};
+ background-color: var(--color-bg-neutral-lightest);
+ text-decoration: none;
+ cursor: ${({ disabled }) => (disabled ? "not-allowed" : "pointer")};
${(props) =>
!props.disabled &&
`
:hover {
- background: var(--color-bg-primary-lighter);
+ background-color: var(--color-bg-primary-lighter);
}
:focus {
outline: var(--border-width-m) var(--border-style-default) var(--border-color-secondary-medium);
- outline-offset: var(--border-width-m);
+ outline-offset: calc(var(--border-width-m) * -1);
}
:active {
- background: var(--color-bg-primary-lighter);
+ background-color: var(--color-bg-primary-lighter);
}
`}
`;
const Label = styled.span<{
disabled: TabProps["disabled"];
- active: TabProps["active"];
}>`
display: inline;
- color: ${(props) => (props.disabled ? "var(--color-fg-neutral-medium)" : "var(--color-fg-neutral-stronger)")};
+ color: ${({ disabled }) => (disabled ? "var(--color-fg-neutral-medium)" : "var(--color-fg-neutral-stronger)")};
font-family: var(--typography-font-family);
font-size: var(--typography-label-l);
font-weight: var(--typography-label-semibold);
@@ -65,27 +62,35 @@ const Label = styled.span<{
white-space: normal;
`;
-const TabIconContainer = styled.div<{
- iconPosition: NavTabsPropsType["iconPosition"];
- active: TabProps["active"];
+const IconContainer = styled.div<{
disabled: TabProps["disabled"];
}>`
display: flex;
+ color: ${({ disabled }) => (disabled ? "var(--color-fg-neutral-medium)" : "var(--color-fg-neutral-stronger)")};
font-size: var(--height-s);
- color: ${(props) => (props.disabled ? "var(--color-fg-neutral-medium)" : "var(--color-fg-neutral-stronger)")};
svg {
height: var(--height-s);
width: 24px;
}
`;
-const DxcTab = forwardRef(
+const Underline = styled.span<{ active: TabProps["active"] }>`
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: var(--border-width-m);
+ background-color: ${({ active }) =>
+ active ? "var(--border-color-primary-stronger)" : "var(--border-color-neutral-medium)"};
+`;
+
+const Tab = forwardRef(
(
{ href, active = false, icon, disabled = false, notificationNumber = false, children, ...otherProps }: TabProps,
ref: Ref
- ): JSX.Element => {
- const tabRef = useRef();
+ ) => {
const { iconPosition, tabIndex, focusedLabel } = useContext(NavTabsContext) ?? {};
+ const tabRef = useRef();
const innerRef = useRef(null);
useImperativeHandle(ref, () => innerRef.current!, []);
@@ -93,7 +98,7 @@ const DxcTab = forwardRef(
if (focusedLabel === children.toString()) {
tabRef?.current?.focus();
}
- }, [focusedLabel]);
+ }, [children, focusedLabel]);
const handleOnKeyDown = (event: KeyboardEvent) => {
switch (event.key) {
@@ -108,51 +113,47 @@ const DxcTab = forwardRef(
};
return (
-
- {
- tabRef.current = anchorRef;
-
- if (ref) {
- if (typeof ref === "function") {
- ref(anchorRef);
- } else {
- innerRef.current = anchorRef;
+
+
+ {
+ tabRef.current = anchorRef;
+ if (ref) {
+ if (typeof ref === "function") ref(anchorRef);
+ else innerRef.current = anchorRef;
}
- }
- }}
- onKeyDown={handleOnKeyDown}
- tabIndex={active ? tabIndex : -1}
- role="tab"
- aria-selected={active}
- aria-disabled={disabled}
- {...otherProps}
- >
- {icon && (
-
- {typeof icon === "string" ? : icon}
-
- )}
-
-
- {notificationNumber && !disabled && (
-
+ }}
+ onKeyDown={handleOnKeyDown}
+ tabIndex={active ? tabIndex : -1}
+ role="tab"
+ aria-selected={active}
+ aria-disabled={disabled}
+ {...otherProps}
+ >
+ {icon && (
+
+ {typeof icon === "string" ? : icon}
+
)}
-
-
+
+
+ {notificationNumber && !disabled && (
+
+ )}
+
+
+
+
);
}
);
-export default DxcTab;
+export default Tab;
diff --git a/packages/lib/src/nav-tabs/utils.ts b/packages/lib/src/nav-tabs/utils.ts
new file mode 100644
index 0000000000..1cc2452f85
--- /dev/null
+++ b/packages/lib/src/nav-tabs/utils.ts
@@ -0,0 +1,39 @@
+import { ReactNode, ReactElement } from "react";
+
+export const getPropInChild = (child: ReactNode, propName: string): string | undefined => {
+ if (child && typeof child === "object" && "props" in child) {
+ const childWithProps = child as ReactElement;
+ if (childWithProps.props[propName]) {
+ return childWithProps.props[propName];
+ } else if (childWithProps.props.children) {
+ return getPropInChild(childWithProps.props.children, propName);
+ }
+ }
+};
+
+export const getLabelFromTab = (child: ReactNode): string | undefined => {
+ if (typeof child === "string") {
+ return child;
+ } else if (child && typeof child === "object" && "props" in child) {
+ const childWithProps = child as ReactElement;
+ return Array.isArray(childWithProps.props.children)
+ ? getLabelFromTab(childWithProps.props.children[0])
+ : getLabelFromTab(childWithProps.props.children);
+ }
+};
+
+export const getPreviousTabIndex = (array: ReactElement[], initialIndex: number): number => {
+ let index = initialIndex === 0 ? array.length - 1 : initialIndex - 1;
+ while (getPropInChild(array[index], "disabled")) {
+ index = index === 0 ? array.length - 1 : index - 1;
+ }
+ return index;
+};
+
+export const getNextTabIndex = (array: ReactElement[], initialIndex: number): number => {
+ let index = initialIndex === array.length - 1 ? 0 : initialIndex + 1;
+ while (getPropInChild(array[index], "disabled")) {
+ index = index === array.length - 1 ? 0 : index + 1;
+ }
+ return index;
+};