Skip to content

Commit 42c0f72

Browse files
authored
NavigationTabs: Add tag prop to allow overriding the underlying nav element (#2868)
## Summary: When NavigationTabs is placed in another `nav` element, NavigationTabs doesn't need to use a `nav` element. By adding the `tag` prop, consumers can customize the underlying element. `tag` defaults to `nav` when not provided Issue: WB-2156 ## Test plan: Confirm setting the tag prop changes the underlying element rendered (`?path=/story/packages-tabs-navigationtabs--tag`) <img width="1471" height="350" alt="image" src="https://github.com/user-attachments/assets/a5134d6c-0412-47cc-8d08-51eae6c4cd7a" /> Author: beaesguerra Reviewers: marcysutton Required Reviewers: Approved By: marcysutton Checks: ✅ 12 checks were successful, ⏭️ 3 checks have been skipped Pull Request URL: #2868
1 parent 5036747 commit 42c0f72

File tree

5 files changed

+58
-3
lines changed

5 files changed

+58
-3
lines changed

.changeset/silver-camels-raise.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@khanacademy/wonder-blocks-tabs": minor
3+
---
4+
5+
NavigationTabs: Add tag prop to allow overriding the underlying nav element

__docs__/wonder-blocks-tabs/navigation-tabs.argtypes.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,14 @@ export default {
2424
type: undefined,
2525
},
2626
},
27+
tag: {
28+
control: {
29+
type: "text",
30+
},
31+
table: {
32+
type: {
33+
summary: "keyof JSX.IntrinsicElements",
34+
},
35+
},
36+
},
2737
} satisfies ArgTypes;

__docs__/wonder-blocks-tabs/navigation-tabs.stories.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,21 @@ export const ChildrenRenderFunction: StoryComponentType = {
456456
chromatic: {delay: 500},
457457
},
458458
};
459+
460+
/**
461+
* By default, the `NavigationTabs` component renders as a `nav` element. If
462+
* the underlying element needs to be changed, the `tag` prop can be used to
463+
* specify the HTML tag to render.
464+
*/
465+
export const Tag: StoryComponentType = {
466+
args: {
467+
children: navigationTabItems,
468+
tag: "div",
469+
},
470+
parameters: {
471+
chromatic: {
472+
// Disabling because this story doesn't test anything visual.
473+
disableSnapshot: true,
474+
},
475+
},
476+
};

packages/wonder-blocks-tabs/src/components/__tests__/navigation-tabs.test.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ describe("NavigationTabs", () => {
3434
expect(nav).toBeInTheDocument();
3535
});
3636

37+
it("should use the tag prop if provided ", async () => {
38+
// Arrange
39+
render(
40+
<NavigationTabs tag="div" testId="navigation-tabs">
41+
{children}
42+
</NavigationTabs>,
43+
);
44+
45+
// Act
46+
const navigationTabs = await screen.findByTestId("navigation-tabs");
47+
48+
// Assert
49+
expect(navigationTabs).toHaveProperty("tagName", "DIV");
50+
});
51+
3752
it("should render a list element", async () => {
3853
// Arrange
3954
render(

packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ type Props = AriaProps & {
4949
* if the user has `prefers-reduced-motion` opted in. Defaults to `false`.
5050
*/
5151
animated?: boolean;
52+
53+
/**
54+
* The HTML tag to render. Defaults to `nav`.
55+
*/
56+
tag?: keyof JSX.IntrinsicElements;
5257
};
5358

54-
const StyledNav = addStyle("nav");
5559
const StyledUl = addStyle("ul");
5660
const StyledDiv = addStyle("div");
5761

@@ -90,9 +94,12 @@ export const NavigationTabs = React.forwardRef(function NavigationTabs(
9094
"aria-labelledby": ariaLabelledBy,
9195
styles: stylesProp,
9296
animated = false,
97+
tag = "nav",
9398
...otherProps
9499
} = props;
95100

101+
const StyledTag = React.useMemo(() => addStyle(tag), [tag]);
102+
96103
/**
97104
* Ref for the list element so we can observe when the size of the children
98105
* changes. This is necessary to update the underline position. We watch the
@@ -117,7 +124,7 @@ export const NavigationTabs = React.forwardRef(function NavigationTabs(
117124
});
118125

119126
return (
120-
<StyledNav
127+
<StyledTag
121128
id={id}
122129
data-testid={testId}
123130
aria-label={ariaLabel}
@@ -136,7 +143,7 @@ export const NavigationTabs = React.forwardRef(function NavigationTabs(
136143
the list so that it can slide between tab items. */}
137144
{<div {...indicatorProps} />}
138145
</StyledDiv>
139-
</StyledNav>
146+
</StyledTag>
140147
);
141148
});
142149

0 commit comments

Comments
 (0)