Repository: Khan/wonder-blocks
Pull request #2508: NavigationTabs Styling
Author: login: beaesguerra
Created: 2025-03-20T19:02:45Z | Merged: 2025-03-25T15:19:13Z

## Summary:

The following changes address various styling requirements and includes adding some tools for testing in Storybook

Props
- NavigationTabs supports `styles` prop and NavigationTabs supports `style` prop for custom styling

Styles
- States for current, press, hover, and focus (using a box shadow) are implemented
- Semantic color and sizing tokens are used (colors may need to be revisited once Thunder Blocks theme is implemented)
- Used box-shadow for the underline. This doesn't conflict with the box-shadow used for the focus outline of the link because the underline is on the parent `<li>` element instead of the `<a>`
- Long labels within the tab won't wrap. No max-width is set at the time to better support translated strings
- The navigation tabs will horizontally scroll if the tabs don't fit on the screen
- Styling is tested with Link, anchor tags, and IconButton
- Handles RTL

Storybook
- Added a decorator and toolbar control to set the language direction
- Added a decorator and toolbar control to set specific zoom presets
- New constants file for text to use for testing different cases (`text-for-testing.ts`)
- New ScenariosLayout component for laying out various scenarios in a list
- Making AllVariants responsive and supporting a list only mode (useful for testing zoom for all variants)


Issue: WB-1898

## Test plan:
- Review stories and docs for NavigationTabs and NavigationTabItem
- Testing rtl, zoom, different browsers, responsiveness


Diff:
diff --git a/.changeset/twenty-actors-tease.md b/.changeset/twenty-actors-tease.md
new file mode 100644
index 0000000000..d51983e50a
--- /dev/null
+++ b/.changeset/twenty-actors-tease.md
@@ -0,0 +1,5 @@
+---
+"@khanacademy/wonder-blocks-tabs": minor
+---
+
+NavigationTabs: Update styles to handle different scenarios
diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx
index c7b5c9b70b..22c5a87f50 100644
--- a/.storybook/preview.tsx
+++ b/.storybook/preview.tsx
@@ -115,9 +115,42 @@ const withThemeSwitcher: Decorator = (
     );
 };
 
+/**
+ * Wraps a story with `<div dir="rtl">` so it is shown in rtl mode.
+ */
+const withLanguageDirection: Decorator = (Story, context) => {
+    if (context.globals.direction === "rtl") {
+        return (
+            <div dir="rtl">
+                <Story />
+            </div>
+        )
+    } else {
+        return <Story />
+    }
+}
+
+/**
+ * Wraps a story with styling that simulates [zoom](https://developer.mozilla.org/en-US/docs/Web/CSS/zoom).
+ *
+ * Note: It is still important to test with real browser zoom in different
+ * browsers. For example, using the CSS zoom property in Safari looks a bit
+ * different than when you zoom in the browser.
+ */
+const withZoom: Decorator = (Story, context) => {
+    if (context.globals.zoom) {
+        return (
+            <div style={{ zoom: context.globals.zoom }}>
+                <Story />
+            </div>
+        )
+    }
+    return <Story />
+}
+
 const preview: Preview = {
     parameters,
-    decorators: [withThemeSwitcher],
+    decorators: [withThemeSwitcher, withLanguageDirection, withZoom],
     globalTypes: {
         // Allow the user to select a theme from the toolbar.
         theme: {
@@ -143,6 +176,48 @@ const preview: Preview = {
                 dynamicTitle: true,
             },
         },
+        direction: {
+            description: "The language direction to use",
+            toolbar: {
+                title: "Language Direction",
+                icon: "globe",
+                items: [
+                    {
+                        value: "ltr",
+                        icon: "arrowrightalt",
+                        title: "Left to Right",
+                    },
+                    {
+                        value: "rtl",
+                        icon: "arrowleftalt",
+                        title: "Right to Left",
+                    },
+                ],
+                dynamicTitle: true,
+            },
+        },
+        zoom: {
+            description: "Preset zoom level",
+            toolbar: {
+                title: "Zoom Presets",
+                icon: "zoom",
+                items: [
+                    {
+                        // undefined so there is no zoom value set
+                        value: undefined,
+                        title: "default",
+                    },
+                    {
+                        value: "2",
+                        title: "200%",
+                    },
+                    {
+                        value: "4",
+                        title: "400%",
+                    },
+                ],
+            },
+        }
     },
 
     tags: ["autodocs"],
diff --git a/__docs__/components/all-variants.tsx b/__docs__/components/all-variants.tsx
index 42f9aafd71..cd64344821 100644
--- a/__docs__/components/all-variants.tsx
+++ b/__docs__/components/all-variants.tsx
@@ -2,10 +2,12 @@ import * as React from "react";
 import type {StrictArgs} from "@storybook/react";
 
 import {StyleSheet} from "aphrodite";
-import {addStyle} from "@khanacademy/wonder-blocks-core";
+import {addStyle, View} from "@khanacademy/wonder-blocks-core";
 import {
     border,
+    breakpoint,
     semanticColor,
+    sizing,
     spacing,
 } from "@khanacademy/wonder-blocks-tokens";
 
@@ -14,6 +16,7 @@ import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
 const StyledTable = addStyle("table");
 const StyledTh = addStyle("th");
 const StyledTd = addStyle("td");
+const StyledUl = addStyle("ul");
 
 type Variant = {name: string; props: StrictArgs};
 
@@ -22,7 +25,7 @@ type Props = {
      * The children as a function that receives the state props used to render
      * each variant of the component.
      */
-    children: (props: any) => React.ReactNode;
+    children: (props: any, name: string) => React.ReactNode;
     /**
      * The categories to display in the table as columns.
      */
@@ -31,52 +34,97 @@ type Props = {
      * The states to display in the table as rows.
      */
     columns: Array<Variant>;
+    /**
+     * The layout for AllVariants.
+     * - `responsive`: variants will be displayed in a table at larger screen
+     * sizes and in a list at smaller screen sizes
+     * - `list`: variants will always be displayed in a list
+     */
+    layout?: "responsive" | "list";
 };
 
 /**
  * A table that displays all possible variants of a component.
  */
-export function AllVariants({children, columns, rows}: Props) {
+export function AllVariants(props: Props) {
+    const {children, rows, columns, layout = "responsive"} = props;
+
     return (
-        <StyledTable style={styles.table}>
-            <thead>
-                <tr>
-                    <StyledTh style={styles.cell}>
-                        <LabelLarge>Category / State</LabelLarge>
-                    </StyledTh>
-                    {columns.map((col, index) => (
-                        <StyledTh key={index} scope="col" style={styles.cell}>
-                            <LabelLarge>{col.name}</LabelLarge>
-                        </StyledTh>
-                    ))}
-                </tr>
-            </thead>
-            <tbody>
-                {rows.map((row, idx) => (
-                    <tr key={idx}>
-                        <StyledTh scope="row" style={styles.cell}>
-                            <LabelLarge>{row.name}</LabelLarge>
-                        </StyledTh>
-                        {columns.map((col) => (
-                            <StyledTd
-                                key={col.name}
-                                style={[
-                                    styles.cell,
-                                    {
-                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
-                                    },
-                                ]}
-                            >
-                                {children({
-                                    ...row.props,
-                                    ...col.props,
-                                })}
-                            </StyledTd>
+        <>
+            {layout === "responsive" && (
+                <StyledTable style={[styles.table]}>
+                    <thead>
+                        <tr>
+                            <StyledTh style={styles.cell}>
+                                <LabelLarge>Category / State</LabelLarge>
+                            </StyledTh>
+                            {columns.map((col, index) => (
+                                <StyledTh
+                                    key={index}
+                                    scope="col"
+                                    style={styles.cell}
+                                >
+                                    <LabelLarge>{col.name}</LabelLarge>
+                                </StyledTh>
+                            ))}
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {rows.map((row, idx) => (
+                            <tr key={idx}>
+                                <StyledTh scope="row" style={styles.cell}>
+                                    <LabelLarge>{row.name}</LabelLarge>
+                                </StyledTh>
+                                {columns.map((col) => (
+                                    <StyledTd
+                                        key={col.name}
+                                        style={[
+                                            styles.cell,
+                                            {
+                                                border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+                                            },
+                                        ]}
+                                    >
+                                        {children(
+                                            {
+                                                ...row.props,
+                                                ...col.props,
+                                            },
+                                            `${row.name} ${col.name}`,
+                                        )}
+                                    </StyledTd>
+                                ))}
+                            </tr>
                         ))}
-                    </tr>
-                ))}
-            </tbody>
-        </StyledTable>
+                    </tbody>
+                </StyledTable>
+            )}
+            <StyledUl
+                style={[
+                    styles.list,
+                    layout === "responsive" && styles.listResponsive,
+                ]}
+            >
+                {rows.map((row) => {
+                    return columns.map((column) => {
+                        return (
+                            <li key={`${row.name} ${column.name}`}>
+                                <LabelLarge>
+                                    Column: {column.name}, Row: {row.name}
+                                </LabelLarge>
+
+                                <View style={styles.childrenWrapper}>
+                                    {children(
+                                        {...column.props, ...row.props},
+                                        `${row.name} ${column.name}`,
+                                    )}
+                                </View>
+                            </li>
+                        );
+                    });
+                })}
+            </StyledUl>
+        </>
     );
 }
 
@@ -84,9 +132,29 @@ const styles = StyleSheet.create({
     table: {
         borderCollapse: "collapse",
         textAlign: "left",
+        [breakpoint.mediaQuery.smOrSmaller]: {
+            display: "none",
+        },
+    },
+    list: {
+        margin: 0,
+        padding: 0,
+        listStyle: "none",
+        display: "flex",
+        flexDirection: "column",
+    },
+    listResponsive: {
+        [breakpoint.mediaQuery.mdOrLarger]: {
+            display: "none",
+        },
     },
     cell: {
         margin: spacing.medium_16,
         padding: spacing.medium_16,
     },
+    childrenWrapper: {
+        padding: sizing.size_100,
+        marginBlock: sizing.size_100,
+        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+    },
 });
diff --git a/__docs__/components/scenarios-layout.tsx b/__docs__/components/scenarios-layout.tsx
new file mode 100644
index 0000000000..3509716540
--- /dev/null
+++ b/__docs__/components/scenarios-layout.tsx
@@ -0,0 +1,43 @@
+import React from "react";
+import type {StrictArgs} from "@storybook/react";
+import {StyleSheet} from "aphrodite";
+import {View} from "@khanacademy/wonder-blocks-core";
+import {LabelLarge} from "@khanacademy/wonder-blocks-typography";
+import {sizing} from "@khanacademy/wonder-blocks-tokens";
+
+type Props = {
+    scenarios: {name: string; props: StrictArgs}[];
+    children: (props: any, name: string) => React.ReactNode;
+};
+
+/**
+ * Useful for stories that show different scenarios.
+ *
+ * Normally, ScenariosLayout is used for different cases at rest state.
+ */
+export const ScenariosLayout = (props: Props) => {
+    const {scenarios, children} = props;
+    return (
+        <View style={styles.container}>
+            {scenarios.map((scenario) => {
+                return (
+                    <View key={scenario.name} style={styles.scenario}>
+                        <LabelLarge>{scenario.name}</LabelLarge>
+                        {children(scenario.props, scenario.name)}
+                    </View>
+                );
+            })}
+        </View>
+    );
+};
+
+const styles = StyleSheet.create({
+    container: {
+        gap: sizing.size_200,
+        alignItems: "flex-start",
+    },
+    scenario: {
+        gap: sizing.size_100,
+        maxWidth: "100%",
+    },
+});
diff --git a/__docs__/components/text-for-testing.ts b/__docs__/components/text-for-testing.ts
new file mode 100644
index 0000000000..70a6f03fae
--- /dev/null
+++ b/__docs__/components/text-for-testing.ts
@@ -0,0 +1,5 @@
+export const rtlText = "هذا الرابط مكتوب باللغة العربية";
+export const longText =
+    "Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua";
+export const longTextWithNoWordBreak =
+    "Loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliqua";
diff --git a/__docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx b/__docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
index a94a5e0295..5e3460f5d5 100644
--- a/__docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
+++ b/__docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
@@ -3,87 +3,136 @@ import * as React from "react";
 
 import {StyleSheet} from "aphrodite";
 
-import {View} from "@khanacademy/wonder-blocks-core";
+import {addStyle, View} from "@khanacademy/wonder-blocks-core";
 import {NavigationTabItem} from "@khanacademy/wonder-blocks-tabs";
 import {sizing} from "@khanacademy/wonder-blocks-tokens";
 import {AllVariants} from "../components/all-variants";
 import Link from "@khanacademy/wonder-blocks-link";
 import {PhosphorIcon} from "@khanacademy/wonder-blocks-icon";
 import {IconMappings} from "../wonder-blocks-icon/phosphor-icon.argtypes";
+import {HeadingLarge} from "@khanacademy/wonder-blocks-typography";
+import {rtlText} from "../components/text-for-testing";
+import IconButton from "@khanacademy/wonder-blocks-icon-button";
 
-const rows = [
-    {name: "Default", props: {}},
-    {
-        name: "External Link",
-        props: {
-            children: (
-                <Link href="https://khanacademy.org" target="_blank">
-                    External link
-                </Link>
-            ),
+const StyledA = addStyle("a");
+const generateRows = (rtl: boolean = false) => {
+    return [
+        {
+            name: "Default",
+            props: {
+                children: (
+                    <Link href="#link">
+                        {rtl ? rtlText : "Navigation Tab Item"}
+                    </Link>
+                ),
+            },
         },
-    },
-    {
-        name: "Start Icon",
-        props: {
-            children: (
-                <Link
-                    href="#link"
-                    startIcon={
-                        <PhosphorIcon icon={IconMappings.cookie} size="small" />
-                    }
-                >
-                    Start Icon
-                </Link>
-            ),
+        {
+            name: "External Link",
+            props: {
+                children: (
+                    <Link href="https://khanacademy.org" target="_blank">
+                        {rtl ? rtlText : "External link"}
+                    </Link>
+                ),
+            },
         },
-    },
-    {
-        name: "End Icon",
-        props: {
-            children: (
-                <Link
-                    href="#link"
-                    endIcon={
-                        <PhosphorIcon
-                            icon={IconMappings.iceCream}
-                            size="small"
-                        />
-                    }
-                >
-                    End Icon
-                </Link>
-            ),
+        {
+            name: "Start Icon",
+            props: {
+                children: (
+                    <Link
+                        href="#link"
+                        startIcon={
+                            <PhosphorIcon
+                                icon={IconMappings.cookie}
+                                size="small"
+                            />
+                        }
+                    >
+                        {rtl ? rtlText : "Start Icon"}
+                    </Link>
+                ),
+            },
         },
-    },
-    {
-        name: "Start and End Icons",
-        props: {
-            children: (
-                <Link
-                    href="#link"
-                    startIcon={
-                        <PhosphorIcon icon={IconMappings.cookie} size="small" />
-                    }
-                    endIcon={
-                        <PhosphorIcon
-                            icon={IconMappings.iceCream}
-                            size="small"
-                        />
-                    }
-                >
-                    Start and End Icons
-                </Link>
-            ),
+        {
+            name: "End Icon",
+            props: {
+                children: (
+                    <Link
+                        href="#link"
+                        endIcon={
+                            <PhosphorIcon
+                                icon={IconMappings.iceCream}
+                                size="small"
+                            />
+                        }
+                    >
+                        {rtl ? rtlText : "End Icon"}
+                    </Link>
+                ),
+            },
         },
-    },
-];
+        {
+            name: "Start and End Icons",
+            props: {
+                children: (
+                    <Link
+                        href="#link"
+                        startIcon={
+                            <PhosphorIcon
+                                icon={IconMappings.cookie}
+                                size="small"
+                            />
+                        }
+                        endIcon={
+                            <PhosphorIcon
+                                icon={IconMappings.iceCream}
+                                size="small"
+                            />
+                        }
+                    >
+                        {rtl ? rtlText : "Start and End Icons"}
+                    </Link>
+                ),
+            },
+        },
+        {
+            name: "Icon only",
+            props: {
+                children: (
+                    <IconButton
+                        href="#link"
+                        aria-label="Ice cream"
+                        icon={IconMappings.iceCream}
+                    />
+                ),
+            },
+        },
+        {
+            name: "Native anchor tag",
+            props: {
+                children: (
+                    <StyledA href="#link">
+                        {rtl ? rtlText : "Anchor tag"}
+                    </StyledA>
+                ),
+            },
+        },
+    ];
+};
 
+const rows = generateRows();
+const rtlRows = generateRows(true);
 const columns = [
     {
         name: "Default",
         props: {},
     },
+    {
+        name: "Current",
+        props: {current: true},
+    },
 ];
 
 type Story = StoryObj<typeof NavigationTabItem>;
@@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <>
+            <AllVariants rows={rows} columns={columns}>
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns}>
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </>
     ),
-    args: {
-        children: <Link href="#link">Navigation Tab Item</Link>,
-    },
     tags: ["!autodocs"],
     parameters: {
         a11y: {
@@ -143,8 +201,42 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </>
+    ),
+    globals: {
+        zoom: "400%",
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because Chromatic crops the story when zoom is used
+            disableSnapshot: true,
+        },
+    },
+};
+
 const styles = StyleSheet.create({
     container: {
         gap: sizing.size_200,
+        alignItems: "flex-start",
     },
 });
diff --git a/__docs__/wonder-blocks-tabs/navigation-tab-item.argtypes.tsx b/__docs__/wonder-blocks-tabs/navigation-tab-item.argtypes.tsx
index 71f4b0f78a..b22d177dce 100644
--- a/__docs__/wonder-blocks-tabs/navigation-tab-item.argtypes.tsx
+++ b/__docs__/wonder-blocks-tabs/navigation-tab-item.argtypes.tsx
@@ -11,4 +11,15 @@ export default {
             },
         },
     },
+    style: {
+        table: {
+            type: {
+                summary: "StyleType",
+            },
+            category: "Visual style",
+        },
+        control: {
+            type: undefined,
+        },
+    },
 } satisfies ArgTypes;
diff --git a/__docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx b/__docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx
index 3ff35b61e7..6f7593fa1a 100644
--- a/__docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx
+++ b/__docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx
@@ -7,8 +7,15 @@ import Link from "@khanacademy/wonder-blocks-link";
 import {View} from "@khanacademy/wonder-blocks-core";
 import {Popover, PopoverContent} from "@khanacademy/wonder-blocks-popover";
 import Tooltip from "@khanacademy/wonder-blocks-tooltip";
-import {sizing} from "@khanacademy/wonder-blocks-tokens";
+import {semanticColor, sizing} from "@khanacademy/wonder-blocks-tokens";
 import argTypes from "./navigation-tab-item.argtypes";
+import {
+    longText,
+    longTextWithNoWordBreak,
+} from "../components/text-for-testing";
+import {PhosphorIcon} from "@khanacademy/wonder-blocks-icon";
+import {IconMappings} from "../wonder-blocks-icon/phosphor-icon.argtypes";
+import {ScenariosLayout} from "../components/scenarios-layout";
 
 export default {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem",
@@ -108,3 +115,104 @@ export const ChildrenRenderFunction: StoryComponentType = {
         chromatic: {delay: 500},
     },
 };
+
+/**
+ * Custom styles can be set for the NavigationTabItem.
+ *
+ * For custom link styling, prefer applying the styles to the `Link` component.
+ * Note: The `NavigationTabItem` will also set styles to the `Link` child
+ * component.
+ *
+ * If there is a specific use case where the styling needs to be
+ * overridden, please reach out to the Wonder Blocks team!
+ */
+export const CustomStyle: StoryComponentType = {
+    args: {
+        children: <Link href="#link">Navigation tab item</Link>,
+        style: {
+            backgroundColor: semanticColor.surface.secondary,
+        },
+    },
+};
+
+/**
+ * The following story shows how the component handles specific scenarios.
+ */
+export const Scenarios: StoryComponentType = {
+    render() {
+        const scenarios = [
+            {
+                name: "Long Text",
+                props: {
+                    current: true,
+                    children: <Link href="#link">{longText}</Link>,
+                },
+            },
+            {
+                name: "Long Text with No Word Break",
+                props: {
+                    current: true,
+                    children: (
+                        <Link href="#link">{longTextWithNoWordBreak}</Link>
+                    ),
+                },
+            },
+            {
+                name: "Long Text (icons)",
+                props: {
+                    current: true,
+                    children: (
+                        <Link
+                            href="#link"
+                            startIcon={
+                                <PhosphorIcon
+                                    icon={IconMappings.cookie}
+                                    size="small"
+                                />
+                            }
+                            endIcon={
+                                <PhosphorIcon
+                                    icon={IconMappings.iceCream}
+                                    size="small"
+                                />
+                            }
+                        >
+                            {longText}
+                        </Link>
+                    ),
+                },
+            },
+            {
+                name: "Long Text with No Word Break (icons)",
+                props: {
+                    current: true,
+                    children: (
+                        <Link
+                            href="#link"
+                            startIcon={
+                                <PhosphorIcon
+                                    icon={IconMappings.cookie}
+                                    size="small"
+                                />
+                            }
+                            endIcon={
+                                <PhosphorIcon
+                                    icon={IconMappings.iceCream}
+                                    size="small"
+                                />
+                            }
+                        >
+                            {longTextWithNoWordBreak}
+                        </Link>
+                    ),
+                },
+            },
+        ];
+
+        return (
+            <ScenariosLayout scenarios={scenarios}>
+                {(props) => <NavigationTabItem {...props} />}
+            </ScenariosLayout>
+        );
+    },
+};
diff --git a/__docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx b/__docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx
index a7237b1df9..ab6d51c8aa 100644
--- a/__docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx
+++ b/__docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx
@@ -3,7 +3,7 @@ import * as React from "react";
 
 import {StyleSheet} from "aphrodite";
 
-import {View} from "@khanacademy/wonder-blocks-core";
+import {addStyle, View} from "@khanacademy/wonder-blocks-core";
 import {
     NavigationTabItem,
     NavigationTabs,
@@ -13,9 +13,39 @@ import {AllVariants} from "../components/all-variants";
 import Link from "@khanacademy/wonder-blocks-link";
 import {PhosphorIcon} from "@khanacademy/wonder-blocks-icon";
 import {IconMappings} from "../wonder-blocks-icon/phosphor-icon.argtypes";
+import {rtlText} from "../components/text-for-testing";
+import IconButton from "@khanacademy/wonder-blocks-icon-button";
 
-const rows = [
-    {name: "Default", props: {"aria-label": "Default navigation tabs"}},
+const StyledA = addStyle("a");
+const generateRows = (rtl: boolean = false) => [
+    {
+        name: "Default",
+        props: {
+            "aria-label": "Default navigation tabs",
+            children: [
+                <NavigationTabItem current={true}>
+                    <Link href="#link1">
+                        {rtl ? rtlText : "Navigation Tab Item 1"}
+                    </Link>
+                </NavigationTabItem>,
+                <NavigationTabItem>
+                    <Link href="#link2">
+                        {rtl ? rtlText : "Navigation Tab Item 2"}
+                    </Link>
+                </NavigationTabItem>,
+                <NavigationTabItem>
+                    <Link href="#link3">
+                        {rtl ? rtlText : "Navigation Tab Item 3"}
+                    </Link>
+                </NavigationTabItem>,
+                <NavigationTabItem>
+                    <Link href="#link4">
+                        {rtl ? rtlText : "Navigation Tab Item 4"}
+                    </Link>
+                </NavigationTabItem>,
+            ],
+        },
+    },
     {
         name: "Link Capabilities",
         props: {
@@ -23,7 +53,7 @@ const rows = [
             children: [
                 <NavigationTabItem>
                     <Link href="https://khanacademy.org" target="_blank">
-                        External Link
+                        {rtl ? rtlText : "External Link"}
                     </Link>
                 </NavigationTabItem>,
                 <NavigationTabItem>
@@ -36,7 +66,7 @@ const rows = [
                             />
                         }
                     >
-                        Start Icon
+                        {rtl ? rtlText : "Start Icon"}
                     </Link>
                 </NavigationTabItem>,
                 <NavigationTabItem>
@@ -49,10 +79,10 @@ const rows = [
                             />
                         }
                     >
-                        End Icon
+                        {rtl ? rtlText : "End Icon"}
                     </Link>
                 </NavigationTabItem>,
-                <NavigationTabItem>
+                <NavigationTabItem current={true}>
                     <Link
                         href="#link4"
                         startIcon={
@@ -68,14 +98,67 @@ const rows = [
                             />
                         }
                     >
-                        Start and End Icons
+                        {rtl ? rtlText : "Start and End Icons"}
                     </Link>
                 </NavigationTabItem>,
             ],
         },
     },
+    {
+        name: "Icon Only",
+        props: {
+            children: [
+                <NavigationTabItem current={true}>
+                    <IconButton
+                        icon={IconMappings.iceCream}
+                        aria-label="Ice cream"
+                        size="medium"
+                        href="#link-1"
+                    />
+                </NavigationTabItem>,
+                <NavigationTabItem>
+                    <IconButton
+                        icon={IconMappings.cookie}
+                        aria-label="Cookie"
+                        size="medium"
+                        href="#link-2"
+                    />
+                </NavigationTabItem>,
+            ],
+        },
+    },
+    {
+        name: "Native anchor links",
+        props: {
+            children: [
+                <NavigationTabItem current={true}>
+                    <StyledA href="#link-1">
+                        {rtl ? rtlText : "Anchor tag 1"}
+                    </StyledA>
+                </NavigationTabItem>,
+                <NavigationTabItem>
+                    <StyledA href="#link-2">
+                        {rtl ? rtlText : "Anchor tag 2"}
+                    </StyledA>
+                </NavigationTabItem>,
+                <NavigationTabItem>
+                    <StyledA href="#link-3">
+                        {rtl ? rtlText : "Anchor tag 3"}
+                    </StyledA>
+                </NavigationTabItem>,
+                <NavigationTabItem>
+                    <StyledA href="#link-4">
+                        {rtl ? rtlText : "Anchor tag 4"}
+                    </StyledA>
+                </NavigationTabItem>,
+            ],
+        },
+    },
 ];
 
+const rows = generateRows();
+const rtlRows = generateRows(true);
+
 const columns = [
     {
         name: "Default",
@@ -93,30 +176,33 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabs / NavigationTabs - All Variants",
     component: NavigationTabs,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabs {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <>
+            <AllVariants rows={rows} columns={columns}>
+                {(props, name) => (
+                    <View style={styles.container}>
+                        <NavigationTabs
+                            {...args}
+                            {...props}
+                            aria-label={name}
+                        />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <AllVariants rows={rtlRows} columns={columns}>
+                    {(props, name) => (
+                        <View style={styles.container}>
+                            <NavigationTabs
+                                {...args}
+                                {...props}
+                                aria-label={`${name} RTL`}
+                            />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </>
     ),
-    args: {
-        children: [
-            <NavigationTabItem>
-                <Link href="#link1">Navigation Tab Item 1</Link>
-            </NavigationTabItem>,
-            <NavigationTabItem>
-                <Link href="#link2">Navigation Tab Item 2</Link>
-            </NavigationTabItem>,
-            <NavigationTabItem>
-                <Link href="#link3">Navigation Tab Item 3</Link>
-            </NavigationTabItem>,
-            <NavigationTabItem>
-                <Link href="#link4">Navigation Tab Item 4</Link>
-            </NavigationTabItem>,
-        ],
-    },
     tags: ["!autodocs"],
 } satisfies Meta<typeof NavigationTabs>;
 
@@ -141,6 +227,58 @@ export const Active: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props, name) => (
+                    <View style={styles.container}>
+                        <NavigationTabs
+                            {...args}
+                            {...props}
+                            aria-label={name}
+                        />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props, name) => (
+                        <View style={styles.container}>
+                            <NavigationTabs
+                                {...args}
+                                {...props}
+                                aria-label={`${name} RTL`}
+                            />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </>
+    ),
+    parameters: {
+        a11y: {
+            config: {
+                rules: [
+                    // Disabling warning: "Element's background color could not
+                    // be determined because it's partially obscured by another
+                    // element" since these examples can cause the horizontal
+                    // scrollbar to show. Color contrast check is enabled for
+                    // other stories (including the AllVariants)
+                    {id: "color-contrast", enabled: false},
+                ],
+            },
+        },
+        chromatic: {
+            // Disabling because Chromatic crops the story when zoom is used
+            disableSnapshot: true,
+        },
+    },
+    globals: {
+        zoom: "400%",
+    },
+};
+
 const styles = StyleSheet.create({
     container: {
         gap: sizing.size_200,
diff --git a/__docs__/wonder-blocks-tabs/navigation-tabs.argtypes.tsx b/__docs__/wonder-blocks-tabs/navigation-tabs.argtypes.tsx
index 1a038514f1..fd01455d79 100644
--- a/__docs__/wonder-blocks-tabs/navigation-tabs.argtypes.tsx
+++ b/__docs__/wonder-blocks-tabs/navigation-tabs.argtypes.tsx
@@ -13,4 +13,15 @@ export default {
             },
         },
     },
+    styles: {
+        table: {
+            type: {
+                summary: "{ root?: StyleType; list?: StyleType; }",
+            },
+            category: "Visual style",
+        },
+        control: {
+            type: undefined,
+        },
+    },
 } satisfies ArgTypes;
diff --git a/__docs__/wonder-blocks-tabs/navigation-tabs.stories.tsx b/__docs__/wonder-blocks-tabs/navigation-tabs.stories.tsx
index 8644aa6547..e6de46ca1e 100644
--- a/__docs__/wonder-blocks-tabs/navigation-tabs.stories.tsx
+++ b/__docs__/wonder-blocks-tabs/navigation-tabs.stories.tsx
@@ -1,5 +1,6 @@
 import * as React from "react";
 import type {Meta, StoryObj} from "@storybook/react";
+import {StyleSheet} from "aphrodite";
 import ComponentInfo from "../components/component-info";
 import packageConfig from "../../packages/wonder-blocks-tabs/package.json";
 import {
@@ -8,6 +9,16 @@ import {
 } from "@khanacademy/wonder-blocks-tabs";
 import Link from "@khanacademy/wonder-blocks-link";
 import argTypes from "./navigation-tabs.argtypes";
+import {semanticColor, sizing} from "@khanacademy/wonder-blocks-tokens";
+import {ScenariosLayout} from "../components/scenarios-layout";
+import {
+    longText,
+    longTextWithNoWordBreak,
+} from "../components/text-for-testing";
+import {PhosphorIcon} from "@khanacademy/wonder-blocks-icon";
+import {IconMappings} from "../wonder-blocks-icon/phosphor-icon.argtypes";
+import {OptionItem, SingleSelect} from "@khanacademy/wonder-blocks-dropdown";
+import {addStyle} from "@khanacademy/wonder-blocks-core";
 
 export default {
     title: "Packages / Tabs / NavigationTabs / NavigationTabs",
@@ -27,7 +38,7 @@ export default {
 type StoryComponentType = StoryObj<typeof NavigationTabs>;
 
 const navigationTabItems = [
-    <NavigationTabItem>
+    <NavigationTabItem current={true}>
         <Link href="#link-1">Navigation tab item 1</Link>
     </NavigationTabItem>,
     <NavigationTabItem>
@@ -49,3 +60,287 @@ export const Default: StoryComponentType = {
         },
     },
 };
+
+/**
+ * Use the `Link` props for setting things like icons.
+ */
+export const WithIcons: StoryComponentType = {
+    args: {
+        children: [
+            <NavigationTabItem>
+                <Link href="https://khanacademy.org" target="_blank">
+                    External Link
+                </Link>
+            </NavigationTabItem>,
+            <NavigationTabItem>
+                <Link
+                    href="#link2"
+                    startIcon={
+                        <PhosphorIcon icon={IconMappings.cookie} size="small" />
+                    }
+                >
+                    Start Icon
+                </Link>
+            </NavigationTabItem>,
+            <NavigationTabItem>
+                <Link
+                    href="#link3"
+                    endIcon={
+                        <PhosphorIcon
+                            icon={IconMappings.iceCream}
+                            size="small"
+                        />
+                    }
+                >
+                    End Icon
+                </Link>
+            </NavigationTabItem>,
+            <NavigationTabItem current={true}>
+                <Link
+                    href="#link4"
+                    startIcon={
+                        <PhosphorIcon icon={IconMappings.cookie} size="small" />
+                    }
+                    endIcon={
+                        <PhosphorIcon
+                            icon={IconMappings.iceCream}
+                            size="small"
+                        />
+                    }
+                >
+                    Start and End Icons
+                </Link>
+            </NavigationTabItem>,
+        ],
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because it's covered by All Variants
+            disableSnapshot: true,
+        },
+    },
+};
+
+/**
+ * Custom styles can be set for the elements in NavigationTabs using the
+ * `styles` prop.
+ *
+ * If there is a specific use case where the styling needs to be
+ * overridden, please reach out to the Wonder Blocks team!
+ */
+export const CustomStyles: StoryComponentType = {
+    args: {
+        children: navigationTabItems,
+        styles: {
+            root: {
+                padding: sizing.size_200,
+            },
+            list: {
+                gap: sizing.size_500,
+            },
+        },
+    },
+};
+
+const generateChildren = (
+    numItems: number,
+    label: string,
+    showIcons: boolean = false,
+) => {
+    return Array(numItems)
+        .fill(0)
+        .map((_, index) => (
+            <NavigationTabItem current={index === 0}>
+                <Link
+                    href={`#link-${index + 1}`}
+                    startIcon={
+                        showIcons ? (
+                            <PhosphorIcon
+                                icon={IconMappings.cookie}
+                                size="small"
+                            />
+                        ) : undefined
+                    }
+                    endIcon={
+                        showIcons ? (
+                            <PhosphorIcon
+                                icon={IconMappings.iceCream}
+                                size="small"
+                            />
+                        ) : undefined
+                    }
+                >
+                    {label}
+                </Link>
+            </NavigationTabItem>
+        ));
+};
+
+/**
+ * The following story shows how the component handles specific scenarios.
+ */
+export const Scenarios: StoryComponentType = {
+    render() {
+        const scenarios = [
+            {
+                name: "Many items",
+                props: {children: generateChildren(10, "Navigation Tab Item")},
+            },
+            {
+                name: "Long text",
+                props: {children: generateChildren(4, longText)},
+            },
+            {
+                name: "Long text with no word break",
+                props: {
+                    children: generateChildren(4, longTextWithNoWordBreak),
+                },
+            },
+            {
+                name: "Long text (with icons)",
+                props: {children: generateChildren(4, longText, true)},
+            },
+            {
+                name: "Long text with no word break (with icons)",
+                props: {
+                    children: generateChildren(
+                        4,
+                        longTextWithNoWordBreak,
+                        true,
+                    ),
+                },
+            },
+            {
+                name: "Varying lengths",
+                props: {
+                    children: [
+                        <NavigationTabItem current={true}>
+                            <Link href="#link-long">{longText}</Link>
+                        </NavigationTabItem>,
+                        <NavigationTabItem>
+                            <Link href="#link-short">Short text</Link>
+                        </NavigationTabItem>,
+                        <NavigationTabItem>
+                            <Link href="#link-long-no-break">
+                                {longTextWithNoWordBreak}
+                            </Link>
+                        </NavigationTabItem>,
+                    ],
+                },
+            },
+        ];
+        return (
+            <ScenariosLayout scenarios={scenarios}>
+                {(props, name) => (
+                    <NavigationTabs {...props} aria-label={name} />
+                )}
+            </ScenariosLayout>
+        );
+    },
+    parameters: {
+        a11y: {
+            config: {
+                rules: [
+                    // Disabling warning: "Element's background color could not
+                    // be determined because it's partially obscured by another
+                    // element" since these examples can cause the horizontal
+                    // scrollbar to show. Color contrast check is enabled for
+                    // other stories (including the AllVariants)
+                    {id: "color-contrast", enabled: false},
+                ],
+            },
+        },
+    },
+};
+
+/**
+ * The following story shows how the component handles specific scenarios at a
+ * small screen size.
+ */
+export const ScenariosSmallScreen: StoryComponentType = {
+    ...Scenarios,
+    parameters: {
+        ...Scenarios.parameters,
+        viewport: {
+            defaultViewport: "small",
+        },
+    },
+};
+
+const StyledHeader = addStyle("header");
+const StyledDiv = addStyle("div");
+
+/**
+ * Here is an example of the `NavigationTabs` component used within a header.
+ *
+ * Note: To line up the header bottom border with the NavigationTabs underline
+ * styling, a negative vertical margin is set on the `NavigationTabs`.
+ */
+export const HeaderWithNavigationTabsExample: StoryComponentType = {
+    render() {
+        // Putting styles in the component so it shows in the code snippet
+        const headerVerticalSpacing = sizing.size_150;
+        const styles = StyleSheet.create({
+            pageStyle: {
+                backgroundColor: semanticColor.surface.secondary,
+                height: "100vh",
+                width: "100vw",
+            },
+            headerStyle: {
+                backgroundColor: semanticColor.surface.primary,
+                display: "flex",
+                alignItems: "center",
+                flexWrap: "wrap",
+                borderBottom: `1px solid ${semanticColor.border.primary}`,
+                gap: sizing.size_300,
+                padding: `${headerVerticalSpacing} ${sizing.size_300}`,
+            },
+            navigationTabsRoot: {
+                // set margin to negative value of header vertical spacing so
+                // that selected indicator lines up with header border
+                margin: `-${headerVerticalSpacing} 0`,
+            },
+        });
+
+        return (
+            <StyledDiv style={styles.pageStyle}>
+                <StyledHeader style={styles.headerStyle}>
+                    <img
+                        src="/logo.svg"
+                        width="40px"
+                        alt="Wonder Blocks logo"
+                    />
+                    <SingleSelect
+                        aria-label="Example select"
+                        placeholder="Placeholder"
+                        selectedValue={"item-1"}
+                        onChange={() => {}}
+                        style={{width: "200px"}}
+                    >
+                        <OptionItem value="item-1" label="Item 1" />
+                        <OptionItem value="item-2" label="Item 2" />
+                    </SingleSelect>
+                    <NavigationTabs
+                        aria-label="Secondary navigation"
+                        styles={{root: styles.navigationTabsRoot}}
+                    >
+                        <NavigationTabItem
+                            current={true} // replace with logic checking if this is the current route
+                        >
+                            <Link href="#link-1">Tab link 1</Link>
+                        </NavigationTabItem>
+                        <NavigationTabItem>
+                            <Link href="#link-2">Tab link 2</Link>
+                        </NavigationTabItem>
+                        <NavigationTabItem>
+                            <Link href="#link-3">Tab link 3</Link>
+                        </NavigationTabItem>
+                    </NavigationTabs>
+                </StyledHeader>
+            </StyledDiv>
+        );
+    },
+    parameters: {
+        layout: "fullscreen",
+    },
+};
diff --git a/packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx b/packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx
index ab9adc48a4..85058e5225 100644
--- a/packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx
+++ b/packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx
@@ -1,8 +1,12 @@
 import {addStyle, AriaProps, StyleType} from "@khanacademy/wonder-blocks-core";
-import {CSSProperties, StyleSheet} from "aphrodite";
+import {StyleSheet} from "aphrodite";
 import * as React from "react";
 import {styles as typographyStyles} from "@khanacademy/wonder-blocks-typography";
-import {semanticColor, sizing} from "@khanacademy/wonder-blocks-tokens";
+import {
+    breakpoint,
+    semanticColor,
+    sizing,
+} from "@khanacademy/wonder-blocks-tokens";
 
 type NavigationTabItemLinkProps = {style: StyleType; "aria-current"?: "page"};
 
@@ -33,6 +37,12 @@ type Props = AriaProps & {
      * styling and aria-current=page will be applied to the Link.
      */
     current?: boolean;
+    /**
+     * Custom styles for overriding default styles. For custom link styling,
+     * prefer applying the styles to the `Link` component. Note: The
+     * `NavigationTabItem` will also set styles to the `Link` child component.
+     */
+    style?: StyleType;
 };
 
 const StyledLi = addStyle("li");
@@ -61,11 +71,15 @@ export const NavigationTabItem = React.forwardRef(function NavigationTabItem(
     props: Props,
     ref: React.ForwardedRef<HTMLLIElement>,
 ) {
-    const {children, id, testId, current, ...otherProps} = props;
+    const {children, id, testId, current, style, ...otherProps} = props;
 
     function renderChildren() {
         const linkProps: NavigationTabItemLinkProps = {
-            style: [typographyStyles.Body, styles.link],
+            style: [
+                typographyStyles.Body,
+                styles.link,
+                current && styles.currentLink,
+            ],
             "aria-current": current ? "page" : undefined,
         };
 
@@ -80,7 +94,7 @@ export const NavigationTabItem = React.forwardRef(function NavigationTabItem(
         <StyledLi
             id={id}
             data-testid={testId}
-            style={styles.root}
+            style={[styles.root, current && styles.current, style]}
             ref={ref}
             {...otherProps}
         >
@@ -89,35 +103,59 @@ export const NavigationTabItem = React.forwardRef(function NavigationTabItem(
     );
 });
 
-const underlineStyles: CSSProperties = {
-    content: '""',
-    display: "block",
-    position: "absolute",
-    bottom: 0,
-    left: 0,
-    right: 0,
-    height: sizing.size_050,
-};
-
 const styles = StyleSheet.create({
     root: {
         listStyle: "none",
         display: "inline-flex",
+        [":has(a:hover)" as any]: {
+            boxShadow: `inset 0 -${sizing.size_025} 0 0 ${semanticColor.action.secondary.progressive.hover.foreground}`,
+        },
+        [":has(a:active)" as any]: {
+            boxShadow: `inset 0 -${sizing.size_075} 0 0 ${semanticColor.action.secondary.progressive.press.foreground}`,
+        },
+        paddingBlockStart: sizing.size_100,
+        paddingBlockEnd: sizing.size_225,
+        [breakpoint.mediaQuery.mdOrLarger]: {
+            paddingBlockStart: sizing.size_250,
+            paddingBlockEnd: sizing.size_300,
+        },
+    },
+    current: {
+        boxShadow: `inset 0 -${sizing.size_050} 0 0 ${semanticColor.action.secondary.progressive.default.foreground}`,
+        [":has(a:hover)" as any]: {
+            // Make sure hover state for current item is the same underline at rest
+            boxShadow: `inset 0 -${sizing.size_050} 0 0 ${semanticColor.action.secondary.progressive.default.foreground}`,
+        },
+    },
+    currentLink: {
+        color: semanticColor.action.secondary.progressive.default.foreground,
     },
     link: {
+        display: "flex",
+        margin: 0,
         color: semanticColor.text.primary,
-        paddingBlock: sizing.size_150,
         paddingInline: 0,
         position: "relative",
+        whiteSpace: "nowrap",
+        textDecoration: "none",
         ":hover": {
             textDecoration: "none",
-            [":after" as any]: {
-                // We use :after to apply underline styles instead of textDecoration
-                // so the underline is shown under icons in Link too
-                ...underlineStyles,
-                backgroundColor:
-                    semanticColor.action.primary.progressive.hover.border,
-            },
+            outline: "none",
+            color: semanticColor.action.secondary.progressive.default
+                .foreground,
+            backgroundColor: "transparent",
+        },
+        ":active": {
+            textDecoration: "none",
+            outline: "none",
+            color: semanticColor.action.secondary.progressive.press.foreground,
+        },
+        ":focus-visible": {
+            color: semanticColor.action.secondary.progressive.default
+                .foreground,
+            outline: "none",
+            boxShadow: `0 0 0 ${sizing.size_025} ${semanticColor.focus.inner}, 0 0 0 ${sizing.size_050} ${semanticColor.focus.outer}`,
+            borderRadius: 0,
         },
     },
 });
diff --git a/packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx b/packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx
index 10911312b4..e40382b597 100644
--- a/packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx
+++ b/packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx
@@ -1,4 +1,4 @@
-import {addStyle, AriaProps} from "@khanacademy/wonder-blocks-core";
+import {addStyle, AriaProps, StyleType} from "@khanacademy/wonder-blocks-core";
 import {sizing} from "@khanacademy/wonder-blocks-tokens";
 import {StyleSheet} from "aphrodite";
 import * as React from "react";
@@ -32,8 +32,19 @@ type Props = AriaProps & {
      * tabs.
      */
     "aria-labelledby"?: string;
+    /**
+     * Custom styles for the elements in NavigationTabs.
+     * - `root`: Styles the root `nav` element.
+     * - `list`: Styles the underlying `ul` element that wraps the
+     * `NavigationTabItem` components
+     */
+    styles?: {
+        root?: StyleType;
+        list?: StyleType;
+    };
 };
 
+const StyledNav = addStyle("nav");
 const StyledUl = addStyle("ul");
 
 /**
@@ -69,27 +80,37 @@ export const NavigationTabs = React.forwardRef(function NavigationTabs(
         children,
         "aria-label": ariaLabel,
         "aria-labelledby": ariaLabelledBy,
+        styles: stylesProp,
         ...otherProps
     } = props;
     return (
-        <nav
+        <StyledNav
             id={id}
             data-testid={testId}
             aria-label={ariaLabel}
             aria-labelledby={ariaLabelledBy}
             ref={ref}
+            style={[styles.nav, stylesProp?.root]}
             {...otherProps}
         >
-            <StyledUl style={styles.list}>{children}</StyledUl>
-        </nav>
+            <StyledUl style={[styles.list, stylesProp?.list]}>
+                {children}
+            </StyledUl>
+        </StyledNav>
     );
 });
 
 const styles = StyleSheet.create({
+    nav: {
+        overflowX: "auto",
+    },
     list: {
-        padding: 0,
-        margin: 0,
+        // Add horizontal padding for focus outline of first/last elements
+        paddingInline: sizing.size_050,
+        paddingBlock: sizing.size_0,
+        margin: sizing.size_0,
         display: "flex",
         gap: sizing.size_200,
+        flexWrap: "nowrap",
     },
 });


Reviews:
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T19:41:34Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T21:32:20Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-20T21:34:26Z
user: login: marcysutton
body: Great work @beaesguerra! I left you a few really tiny suggestions. Excited to see this component in the wild!
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-20T22:23:27Z
user: login: jandrade
body: Thanks for working on this and adding all these a11y features, it is going to be REALLY useful in general. I've left some comments for you to consider before giving a final approval.
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T15:15:46Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:33:55Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:34:47Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:39:00Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:46:34Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:47:14Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:54:43Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T19:55:35Z
user: login: jandrade
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T20:07:49Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T20:37:04Z
user: login: beaesguerra
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-21T22:41:01Z
user: login: jandrade
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T14:42:17Z
user: login: jandrade
body: LGTM! Thank you for iterating on the Zoom story. Hopefully the Chromatic team will now how to fix that (or apply a patch to this issue). 🚀 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-25T14:44:47Z

Review comments:
diff_hunk: @@ -115,9 +115,42 @@ const withThemeSwitcher: Decorator = (
     );
 };
 
+/**
+ * Wraps a story with `<div dir="rtl">` so it is shown in rtl mode.
+ */
+const withLanguageDirection: Decorator = (Story, context) => {
+    if (context.globals.direction === "rtl") {
+        return (
+            <div dir="rtl">
+                <Story />
+            </div>
+        )
+    } else {
+        return <Story />
+    }
+}
+
+/**
+ * Wraps a story with styling that simulates [zoom](https://developer.mozilla.org/en-US/docs/Web/CSS/zoom).
+ *
+ * Note: It is still important to test with real browser zoom in different
+ * browsers. For example, using the CSS zoom property in Safari looks a bit
+ * different than when you zoom in the browser.
+ */
+const withZoom: Decorator = (Story, context) => {
+    if (context.globals.zoom) {
+        return (
+            <div style={{ zoom: context.globals.zoom }}>
path: .storybook/preview.tsx
user: login: beaesguerra
body: I was trying to find a way for us to easily configure a story to be a specific zoom level so we can have some Chromatic tests covering those cases too. I came across the [CSS zoom property](https://developer.mozilla.org/en-US/docs/Web/CSS/zoom) to control magnification
created_at: 2025-03-20T19:35:17Z
author_association: MEMBER
diff_hunk: @@ -143,6 +176,48 @@ const preview: Preview = {
                 dynamicTitle: true,
             },
         },
+        direction: {
+            description: "The language direction to use",
+            toolbar: {
+                title: "Language Direction",
+                icon: "globe",
+                items: [
+                    {
+                        value: "ltr",
+                        icon: "arrowrightalt",
+                        title: "Left to Right",
+                    },
+                    {
+                        value: "rtl",
+                        icon: "arrowleftalt",
+                        title: "Right to Left",
+                    },
+                ],
+                dynamicTitle: true,
+            },
+        },
+        zoom: {
+            description: "Preset zoom level",
+            toolbar: {
+                title: "Zoom Presets",
+                icon: "zoom",
+                items: [
+                    {
+                        // undefined so the there is no zoom value set
+                        value: undefined,
+                        title: "default",
+                    },
+                    {
+                        value: "2",
+                        title: "200%",
+                    },
+                    {
+                        value: "4",
+                        title: "400%",
+                    },
+                ],
+            },
+        }
path: .storybook/preview.tsx
user: login: beaesguerra
body: There are 2 new controls in our toolbar! We can also configure these global parameters for specific stories

<img width="200" alt="Screenshot 2025-03-20 at 1 33 43 PM" src="https://github.com/user-attachments/assets/e39bff21-631a-468d-a472-9a96097abc82" />

<img width="206" alt="Screenshot 2025-03-20 at 1 36 04 PM" src="https://github.com/user-attachments/assets/18741abf-492f-41be-b0af-8b255449dee2" />


created_at: 2025-03-20T19:36:44Z
author_association: MEMBER
diff_hunk: @@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
+            <AllVariants rows={rows} columns={columns}>
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: beaesguerra
body: Including the rtl block as part of the same all variants story so that it can be covered in the different states (hover, focus, etc)
created_at: 2025-03-20T19:40:02Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,36 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    globals: {
+        zoom: "400%",
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: beaesguerra
body: Here's an example of how we can configure the new zoom decorator!
created_at: 2025-03-20T19:40:31Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,42 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    globals: {
+        zoom: "400%",
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because Chromatic crops the story when zoom is used
+            disableSnapshot: true,
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: beaesguerra
body: I disabled the Zoom stories in Chromatic because the stories would get cropped in the snapshots 😢 here is an [example in Chromatic](https://www.chromatic.com/test?appId=5e1bf4b385e3fb0020b7073c&id=67dc6d67c5e1fc7d3d894464). I tried some things to address this but couldn't get it working. Let me know if you have other ideas!
- setting the `viewport` config for Chromatic for that story
- adding a delay for the snapshot
- setting width: 100% on the decorator

![image](https://github.com/user-attachments/assets/1e6ef3d8-4a1e-4a47-8b8b-e87e37537fcf)

created_at: 2025-03-20T21:31:59Z
author_association: MEMBER
diff_hunk: @@ -89,35 +103,55 @@ export const NavigationTabItem = React.forwardRef(function NavigationTabItem(
     );
 });
 
-const underlineStyles: CSSProperties = {
-    content: '""',
-    display: "block",
-    position: "absolute",
-    bottom: 0,
-    left: 0,
-    right: 0,
-    height: sizing.size_050,
-};
-
 const styles = StyleSheet.create({
     root: {
         listStyle: "none",
         display: "inline-flex",
+        [":has(a:hover)" as any]: {
+            boxShadow: `inset 0 -${sizing.size_050} 0 0 ${semanticColor.action.secondary.progressive.hover.foreground}`,
path: packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx
user: login: beaesguerra
body: I mostly used the secondary action semantic tokens. We may need to revisit this though once Thunder Blocks theming is in place. ([related Figma thread](https://www.figma.com/design/EuFu0U7gqc1koXm8ZhlOLp?node-id=5507-1646#1181055789))
created_at: 2025-03-20T21:34:26Z
author_association: MEMBER
diff_hunk: @@ -108,3 +115,104 @@ export const ChildrenRenderFunction: StoryComponentType = {
         chromatic: {delay: 500},
     },
 };
+
+/**
+ * Custom styles can be set for the NavigationTabItem.
+ *
+ * For custom link styling, prefer applying the styles to the `Link` component.
+ * Note: The `NavigationTabItem` will also set styles to the `Link` child
+ * component.
+ *
+ * If there is a specific use case where the styling needs to be
+ * overridden, please reach out to the Wonder Blocks team!
+ */
+export const CustomStyle: StoryComponentType = {
+    args: {
+        children: <Link href="#link">Navigation tab item</Link>,
+        style: {
+            padding: sizing.size_100,
+        },
+    },
+};
+
+/**
+ * The following story shows how the component habdles specific scenarios.
path: __docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx
user: login: marcysutton
body: **nit:** tiny typo!
```suggestion
 * The following story shows how the component handles specific scenarios.
```
created_at: 2025-03-20T21:53:46Z
author_association: MEMBER
diff_hunk: @@ -143,6 +176,48 @@ const preview: Preview = {
                 dynamicTitle: true,
             },
         },
+        direction: {
+            description: "The language direction to use",
+            toolbar: {
+                title: "Language Direction",
+                icon: "globe",
+                items: [
+                    {
+                        value: "ltr",
+                        icon: "arrowrightalt",
+                        title: "Left to Right",
+                    },
+                    {
+                        value: "rtl",
+                        icon: "arrowleftalt",
+                        title: "Right to Left",
+                    },
+                ],
+                dynamicTitle: true,
+            },
+        },
+        zoom: {
+            description: "Preset zoom level",
+            toolbar: {
+                title: "Zoom Presets",
+                icon: "zoom",
+                items: [
+                    {
+                        // undefined so the there is no zoom value set
path: .storybook/preview.tsx
user: login: marcysutton
body: **nit:** extra word?

```suggestion
                        // undefined so there is no zoom value set
```
created_at: 2025-03-20T22:02:40Z
author_association: MEMBER
diff_hunk: @@ -31,59 +34,125 @@ type Props = {
      * The states to display in the table as rows.
      */
     columns: Array<Variant>;
+    /**
+     * The layout for AllVariants.
+     * - `responsive`: variants will be displayed in a table at larger screen
+     * sizes and in a list at smaller screen sizes
+     * - `list`: variants will always be displayed in a list
+     */
+    layout?: "responsive" | "list";
 };
 
 /**
  * A table that displays all possible variants of a component.
  */
-export function AllVariants({children, columns, rows}: Props) {
+export function AllVariants(props: Props) {
+    const {children, rows, columns, layout = "responsive"} = props;
+
     return (
-        <StyledTable style={styles.table}>
-            <thead>
-                <tr>
-                    <StyledTh style={styles.cell}>
-                        <LabelLarge>Category / State</LabelLarge>
-                    </StyledTh>
-                    {columns.map((col, index) => (
-                        <StyledTh key={index} scope="col" style={styles.cell}>
-                            <LabelLarge>{col.name}</LabelLarge>
-                        </StyledTh>
-                    ))}
-                </tr>
-            </thead>
-            <tbody>
-                {rows.map((row, idx) => (
-                    <tr key={idx}>
-                        <StyledTh scope="row" style={styles.cell}>
-                            <LabelLarge>{row.name}</LabelLarge>
-                        </StyledTh>
-                        {columns.map((col) => (
-                            <StyledTd
-                                key={col.name}
-                                style={[
-                                    styles.cell,
-                                    {
-                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
-                                    },
-                                ]}
-                            >
-                                {children({
-                                    ...row.props,
-                                    ...col.props,
-                                })}
-                            </StyledTd>
+        <>
+            {layout === "responsive" && (
+                <StyledTable style={[styles.table]}>
+                    <thead>
+                        <tr>
+                            <StyledTh style={styles.cell}>
+                                <LabelLarge>Category / State</LabelLarge>
+                            </StyledTh>
+                            {columns.map((col, index) => (
+                                <StyledTh
+                                    key={index}
+                                    scope="col"
+                                    style={styles.cell}
+                                >
+                                    <LabelLarge>{col.name}</LabelLarge>
+                                </StyledTh>
+                            ))}
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {rows.map((row, idx) => (
+                            <tr key={idx}>
+                                <StyledTh scope="row" style={styles.cell}>
+                                    <LabelLarge>{row.name}</LabelLarge>
+                                </StyledTh>
+                                {columns.map((col) => (
+                                    <StyledTd
+                                        key={col.name}
+                                        style={[
+                                            styles.cell,
+                                            {
+                                                border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+                                            },
+                                        ]}
+                                    >
+                                        {children(
+                                            {
+                                                ...row.props,
+                                                ...col.props,
+                                            },
+                                            `${row.name} ${col.name}`,
path: __docs__/components/all-variants.tsx
user: login: marcysutton
body: Oh interesting, I just did something super similar in #2509!
created_at: 2025-03-20T22:03:46Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,36 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    globals: {
+        zoom: "400%",
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: marcysutton
body: That is so useful!!
created_at: 2025-03-20T22:05:55Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,42 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    globals: {
+        zoom: "400%",
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because Chromatic crops the story when zoom is used
+            disableSnapshot: true,
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: marcysutton
body: Weird. Maybe try `min-width: 100vw`, and/or some borders to see if you can determine which top-level element is being cut off?
created_at: 2025-03-20T22:09:27Z
author_association: MEMBER
diff_hunk: @@ -141,6 +227,58 @@ export const Active: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props, name) => (
+                    <View style={styles.container}>
+                        <NavigationTabs
+                            {...args}
+                            {...props}
+                            aria-label={name}
+                        />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props, name) => (
+                        <View style={styles.container}>
+                            <NavigationTabs
+                                {...args}
+                                {...props}
+                                aria-label={`${name} RTL`}
+                            />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    parameters: {
+        a11y: {
+            config: {
+                rules: [
+                    // Disabling warning: "Element's background color could not
path: __docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx
user: login: marcysutton
body: I'm curious about this one, as I wrote part of the overlapping logic in the color-contrast rule! It looks like the Axe extension doesn't surface incompletes anymore, and I don't see any Needs Review items in Accessibility Insights either. Maybe Storybook is using an older axe-core API version?
created_at: 2025-03-20T22:18:43Z
author_association: MEMBER
diff_hunk: @@ -49,3 +60,286 @@ export const Default: StoryComponentType = {
         },
     },
 };
+
+/**
+ * Use the `Link` props for setting things like icons.
+ */
+export const WithIcons: StoryComponentType = {
+    args: {
+        children: [
+            <NavigationTabItem>
+                <Link href="https://khanacademy.org" target="_blank">
+                    External Link
+                </Link>
+            </NavigationTabItem>,
+            <NavigationTabItem>
+                <Link
+                    href="#link2"
+                    startIcon={
+                        <PhosphorIcon icon={IconMappings.cookie} size="small" />
+                    }
+                >
+                    Start Icon
+                </Link>
+            </NavigationTabItem>,
+            <NavigationTabItem>
+                <Link
+                    href="#link3"
+                    endIcon={
+                        <PhosphorIcon
+                            icon={IconMappings.iceCream}
+                            size="small"
+                        />
+                    }
+                >
+                    End Icon
+                </Link>
+            </NavigationTabItem>,
+            <NavigationTabItem current={true}>
+                <Link
+                    href="#link4"
+                    startIcon={
+                        <PhosphorIcon icon={IconMappings.cookie} size="small" />
+                    }
+                    endIcon={
+                        <PhosphorIcon
+                            icon={IconMappings.iceCream}
+                            size="small"
+                        />
+                    }
+                >
+                    Start and End Icons
+                </Link>
+            </NavigationTabItem>,
+        ],
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because it's covered by All Variants
+            disableSnapshot: true,
+        },
+    },
+};
+
+/**
+ * Custom styles can be set for the elements in NavigationTabs using the
+ * `styles` prop.
+ *
+ * If there is a specific use case where the styling needs to be
+ * overridden, please reach out to the Wonder Blocks team!
+ */
+export const CustomStyles: StoryComponentType = {
+    args: {
+        children: navigationTabItems,
+        styles: {
+            root: {
+                padding: sizing.size_200,
+            },
+            list: {
+                gap: sizing.size_500,
+            },
+        },
+    },
+};
+
+const generateChildren = (
+    numItems: number,
+    label: string,
+    showIcons: boolean = false,
+) => {
+    return Array(numItems)
+        .fill(0)
+        .map((_, index) => (
+            <NavigationTabItem current={index === 0}>
+                <Link
+                    href={`#link-${index + 1}`}
+                    startIcon={
+                        showIcons ? (
+                            <PhosphorIcon
+                                icon={IconMappings.cookie}
+                                size="small"
+                            />
+                        ) : undefined
+                    }
+                    endIcon={
+                        showIcons ? (
+                            <PhosphorIcon
+                                icon={IconMappings.iceCream}
+                                size="small"
+                            />
+                        ) : undefined
+                    }
+                >
+                    {label}
+                </Link>
+            </NavigationTabItem>
+        ));
+};
+
+/**
+ * The following story shows how the component habdles specific scenarios.
+ */
+export const Scenarios: StoryComponentType = {
+    render() {
+        const scenarios = [
+            {
+                name: "Many items",
+                props: {children: generateChildren(10, "Navigation Tab Item")},
+            },
+            {
+                name: "Long text",
+                props: {children: generateChildren(4, longText)},
+            },
+            {
+                name: "Long text with no word break",
+                props: {
+                    children: generateChildren(4, longTextWithNoWordBreak),
+                },
+            },
+            {
+                name: "Long text (with icons)",
+                props: {children: generateChildren(4, longText, true)},
+            },
+            {
+                name: "Long text with no word break (with icons)",
+                props: {
+                    children: generateChildren(
+                        4,
+                        longTextWithNoWordBreak,
+                        true,
+                    ),
+                },
+            },
+            {
+                name: "Varying lengths",
+                props: {
+                    children: [
+                        <NavigationTabItem current={true}>
+                            <Link href="#link-long">{longText}</Link>
+                        </NavigationTabItem>,
+                        <NavigationTabItem>
+                            <Link href="#link-short">Short text</Link>
+                        </NavigationTabItem>,
+                        <NavigationTabItem>
+                            <Link href="#link-long-no-break">
+                                {longTextWithNoWordBreak}
+                            </Link>
+                        </NavigationTabItem>,
+                    ],
+                },
+            },
+        ];
+        return (
+            <ScenariosLayout scenarios={scenarios}>
+                {(props, name) => (
+                    <NavigationTabs {...props} aria-label={name} />
+                )}
+            </ScenariosLayout>
+        );
+    },
+    parameters: {
+        a11y: {
+            config: {
+                rules: [
+                    // Disabling warning: "Element's background color could not
+                    // be determined because it's partially obscured by another
+                    // element" since these examples can cause the horizontal
+                    // scrollbar to show. Color contrast check is enabled for
+                    // other stories (including the AllVariants)
+                    {id: "color-contrast", enabled: false},
+                ],
+            },
+        },
+    },
+};
+
+/**
+ * The following story shows how the component habdles specific scenarios at a
+ * small screen size.
+ */
+export const ScenariosSmallScreen: StoryComponentType = {
+    ...Scenarios,
+    parameters: {
+        ...Scenarios.parameters,
+        viewport: {
+            defaultViewport: "small",
+        },
+    },
+};
+
+const StyledHeader = addStyle("header");
+const StyledDiv = addStyle("div");
+
+/**
+ * Here is an example of the `NavigationTabs` component used within a header.
+ *
+ * Note: To line up the header bottom border with the NavigationTabs underline
+ * styling, a negative vertical margin is set on the `NavigationTabs`.
+ */
+export const HeaderWithNavigationTabsExample: StoryComponentType = {
+    render() {
+        // Putting styles in the component so it shows in the code snippet
+        const headerVerticalSpacing = sizing.size_150;
+        const styles = StyleSheet.create({
+            pageStyle: {
+                backgroundColor: semanticColor.surface.secondary,
+                height: "100vh",
+                width: "100vw",
+            },
+            headerStyle: {
+                backgroundColor: semanticColor.surface.primary,
+                display: "flex",
+                alignItems: "center",
+                flexWrap: "wrap",
+                borderBottom: `1px solid ${semanticColor.border.primary}`,
+                gap: sizing.size_300,
+                padding: `${headerVerticalSpacing} ${sizing.size_300}`,
+            },
+            navigationTabsRoot: {
+                // set margin to negative value of header vertical spacing so
+                // that selected indicator lines up with header border
+                margin: `-${headerVerticalSpacing} 0`,
+            },
+        });
+
+        return (
+            <StyledDiv style={styles.pageStyle}>
+                <StyledHeader style={styles.headerStyle}>
+                    <img
+                        src="/logo.svg"
+                        width="40px"
+                        alt="Wonder Blocks logo"
+                    />
+                    <SingleSelect
+                        placeholder="Placeholder"
path: __docs__/wonder-blocks-tabs/navigation-tabs.stories.tsx
user: login: marcysutton
body: This one needs a label with the new API!

```suggestion
                        aria-label="Dropdown"
                        placeholder="Placeholder"
```
created_at: 2025-03-20T22:22:11Z
author_association: MEMBER
path: __docs__/components/text-for-testing.ts
user: login: jandrade
body: **praise:** This is super useful!
created_at: 2025-03-21T14:54:46Z
author_association: MEMBER
diff_hunk: @@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
+            <AllVariants rows={rows} columns={columns}>
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: jandrade
body: Nice! I did something similar with `Link` here: https://github.com/Khan/wonder-blocks/blob/b6d77dc2f1106984c4d9187d4be272ef0a265791/__docs__/wonder-blocks-link/link-variants.stories.tsx#L56-L90
created_at: 2025-03-21T15:00:01Z
author_association: MEMBER
diff_hunk: @@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
+            <AllVariants rows={rows} columns={columns}>
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: jandrade
body: For later.... it would be nice defining a general pattern in `all-variants.tsx` to include RTL by default, but we can define that later if needed.
created_at: 2025-03-21T15:00:43Z
author_association: MEMBER
diff_hunk: @@ -31,59 +34,125 @@ type Props = {
      * The states to display in the table as rows.
      */
     columns: Array<Variant>;
+    /**
+     * The layout for AllVariants.
+     * - `responsive`: variants will be displayed in a table at larger screen
+     * sizes and in a list at smaller screen sizes
+     * - `list`: variants will always be displayed in a list
+     */
+    layout?: "responsive" | "list";
 };
 
 /**
  * A table that displays all possible variants of a component.
  */
-export function AllVariants({children, columns, rows}: Props) {
+export function AllVariants(props: Props) {
+    const {children, rows, columns, layout = "responsive"} = props;
+
     return (
-        <StyledTable style={styles.table}>
-            <thead>
-                <tr>
-                    <StyledTh style={styles.cell}>
-                        <LabelLarge>Category / State</LabelLarge>
-                    </StyledTh>
-                    {columns.map((col, index) => (
-                        <StyledTh key={index} scope="col" style={styles.cell}>
-                            <LabelLarge>{col.name}</LabelLarge>
-                        </StyledTh>
-                    ))}
-                </tr>
-            </thead>
-            <tbody>
-                {rows.map((row, idx) => (
-                    <tr key={idx}>
-                        <StyledTh scope="row" style={styles.cell}>
-                            <LabelLarge>{row.name}</LabelLarge>
-                        </StyledTh>
-                        {columns.map((col) => (
-                            <StyledTd
-                                key={col.name}
-                                style={[
-                                    styles.cell,
-                                    {
-                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
-                                    },
-                                ]}
-                            >
-                                {children({
-                                    ...row.props,
-                                    ...col.props,
-                                })}
-                            </StyledTd>
+        <>
+            {layout === "responsive" && (
+                <StyledTable style={[styles.table]}>
+                    <thead>
+                        <tr>
+                            <StyledTh style={styles.cell}>
+                                <LabelLarge>Category / State</LabelLarge>
+                            </StyledTh>
+                            {columns.map((col, index) => (
+                                <StyledTh
+                                    key={index}
+                                    scope="col"
+                                    style={styles.cell}
+                                >
+                                    <LabelLarge>{col.name}</LabelLarge>
+                                </StyledTh>
+                            ))}
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {rows.map((row, idx) => (
+                            <tr key={idx}>
+                                <StyledTh scope="row" style={styles.cell}>
+                                    <LabelLarge>{row.name}</LabelLarge>
+                                </StyledTh>
+                                {columns.map((col) => (
+                                    <StyledTd
+                                        key={col.name}
+                                        style={[
+                                            styles.cell,
+                                            {
+                                                border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+                                            },
+                                        ]}
+                                    >
+                                        {children(
+                                            {
+                                                ...row.props,
+                                                ...col.props,
+                                            },
+                                            `${row.name} ${col.name}`,
+                                        )}
+                                    </StyledTd>
+                                ))}
+                            </tr>
                         ))}
-                    </tr>
-                ))}
-            </tbody>
-        </StyledTable>
+                    </tbody>
+                </StyledTable>
+            )}
+            <StyledUl
+                style={[
+                    styles.list,
+                    layout === "responsive" && styles.listResponsive,
+                ]}
+            >
+                {rows.map((row) => {
+                    return columns.map((column) => {
+                        return (
+                            <li key={`${row.name} ${column.name}`}>
+                                <LabelLarge>
+                                    Column: {column.name}, Row: {row.name}
+                                </LabelLarge>
+
+                                <div
+                                    style={{
+                                        padding: sizing.size_100,
+                                        marginBlock: sizing.size_100,
+                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+                                    }}
+                                >
path: __docs__/components/all-variants.tsx
user: login: jandrade
body: **suggestion:** It would be great switching to `View` (or `StyledDiv` if view doesn't fit) to prevent inlining the CSS in the html.

```suggestion
                                <View
                                    style={{
                                        padding: sizing.size_100,
                                        marginBlock: sizing.size_100,
                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
                                    }}
                                >
```

Expanding on this, the styles could be moved to the `styles` object as well.
created_at: 2025-03-21T15:03:35Z
author_association: MEMBER
diff_hunk: @@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: jandrade
body: **suggestion:** You could also use a fragment to avoid adding extra divs.

```suggestion
        <>
```


created_at: 2025-03-21T15:05:01Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,42 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: jandrade
body: ```suggestion
        <>
```
created_at: 2025-03-21T15:05:21Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,42 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    globals: {
+        zoom: "400%",
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because Chromatic crops the story when zoom is used
+            disableSnapshot: true,
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: jandrade
body: have you tried using `viewports`?

https://github.com/Khan/wonder-blocks/blob/f03298f1f07c8a5f3c987eec8be7c31c5d2a6b35/__docs__/wonder-blocks-button/button-variants.stories.tsx#L20-L25
created_at: 2025-03-21T15:06:16Z
author_association: MEMBER
diff_hunk: @@ -108,3 +115,104 @@ export const ChildrenRenderFunction: StoryComponentType = {
         chromatic: {delay: 500},
     },
 };
+
+/**
+ * Custom styles can be set for the NavigationTabItem.
+ *
+ * For custom link styling, prefer applying the styles to the `Link` component.
+ * Note: The `NavigationTabItem` will also set styles to the `Link` child
+ * component.
+ *
+ * If there is a specific use case where the styling needs to be
+ * overridden, please reach out to the Wonder Blocks team!
+ */
+export const CustomStyle: StoryComponentType = {
path: __docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx
user: login: jandrade
body: **suggestion:** By looking at the example, this could be disabled in Chromatic (unless you expect to introduce more visual changes).
created_at: 2025-03-21T15:06:59Z
author_association: MEMBER
diff_hunk: @@ -93,30 +176,33 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabs / NavigationTabs - All Variants",
     component: NavigationTabs,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabs {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
path: __docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx
user: login: jandrade
body: ```suggestion
        <>
```
created_at: 2025-03-21T15:07:19Z
author_association: MEMBER
diff_hunk: @@ -141,6 +227,58 @@ export const Active: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
path: __docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx
user: login: jandrade
body: ```suggestion
        <>
```
created_at: 2025-03-21T15:07:27Z
author_association: MEMBER
diff_hunk: @@ -89,35 +103,55 @@ export const NavigationTabItem = React.forwardRef(function NavigationTabItem(
     );
 });
 
-const underlineStyles: CSSProperties = {
-    content: '""',
-    display: "block",
-    position: "absolute",
-    bottom: 0,
-    left: 0,
-    right: 0,
-    height: sizing.size_050,
-};
-
 const styles = StyleSheet.create({
     root: {
         listStyle: "none",
         display: "inline-flex",
+        [":has(a:hover)" as any]: {
+            boxShadow: `inset 0 -${sizing.size_050} 0 0 ${semanticColor.action.secondary.progressive.hover.foreground}`,
+        },
+        [":has(a:active)" as any]: {
+            boxShadow: `inset 0 -${sizing.size_075} 0 0 ${semanticColor.action.secondary.progressive.press.foreground}`,
+        },
+        paddingBlockStart: sizing.size_100,
+        paddingBlockEnd: sizing.size_225,
+        [breakpoint.mediaQuery.mdOrLarger]: {
+            paddingBlockStart: sizing.size_250,
+            paddingBlockEnd: sizing.size_300,
+        },
+    },
+    current: {
+        boxShadow: `inset 0 -${sizing.size_050} 0 0 ${semanticColor.action.secondary.progressive.default.foreground}`,
+    },
+    currentLink: {
+        color: semanticColor.action.secondary.progressive.default.foreground,
     },
     link: {
+        display: "flex",
+        margin: 0,
         color: semanticColor.text.primary,
-        paddingBlock: sizing.size_150,
         paddingInline: 0,
         position: "relative",
+        whiteSpace: "nowrap",
+        textDecoration: "none",
         ":hover": {
             textDecoration: "none",
-            [":after" as any]: {
-                // We use :after to apply underline styles instead of textDecoration
-                // so the underline is shown under icons in Link too
-                ...underlineStyles,
-                backgroundColor:
-                    semanticColor.action.primary.progressive.hover.border,
-            },
+            outline: "none",
+            color: semanticColor.action.secondary.progressive.default
+                .foreground,
+            backgroundColor: "transparent",
+        },
+        ":active": {
+            textDecoration: "none",
+            outline: "none",
+            color: semanticColor.action.secondary.progressive.press.foreground,
+        },
+        ":focus-visible": {
+            color: semanticColor.action.secondary.progressive.default
+                .foreground,
+            outline: "none",
+            boxShadow: `0 0 0 ${sizing.size_025} ${semanticColor.focus.inner}, 0 0 0 ${sizing.size_050} ${semanticColor.focus.outer}`,
path: packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx
user: login: jandrade
body: **praise:** Yay!! it is great finally seeing both semantic focus tokens in place 🎉 
created_at: 2025-03-21T15:09:15Z
author_association: MEMBER
diff_hunk: @@ -89,35 +103,55 @@ export const NavigationTabItem = React.forwardRef(function NavigationTabItem(
     );
 });
 
-const underlineStyles: CSSProperties = {
-    content: '""',
-    display: "block",
-    position: "absolute",
-    bottom: 0,
-    left: 0,
-    right: 0,
-    height: sizing.size_050,
-};
-
 const styles = StyleSheet.create({
     root: {
         listStyle: "none",
         display: "inline-flex",
+        [":has(a:hover)" as any]: {
+            boxShadow: `inset 0 -${sizing.size_050} 0 0 ${semanticColor.action.secondary.progressive.hover.foreground}`,
path: packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx
user: login: jandrade
body: **question:** Do you know if this is the right box-shadow width? I was looking at the design specs, and it looks like the underline width for `hover` is `2px (size_025)`.
created_at: 2025-03-21T15:14:06Z
author_association: MEMBER
diff_hunk: @@ -32,8 +32,16 @@ type Props = AriaProps & {
      * tabs.
      */
     "aria-labelledby"?: string;
+    /**
+     * Custom styles for the elements in NavigationTabs.
+     */
+    styles?: {
+        root?: StyleType;
+        list?: StyleType;
path: packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx
user: login: jandrade
body: **thought:** What do you think about extending the description a bit to specify what `root` and `list` are specifically for?
created_at: 2025-03-21T15:14:48Z
author_association: MEMBER
diff_hunk: @@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
+            <AllVariants rows={rows} columns={columns}>
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: beaesguerra
body: Haha yes I was referencing your work for the AllVariants with rtl!

 > For later.... it would be nice defining a general pattern in all-variants.tsx to include RTL by default, but we can define that later if needed.

While working on this, I attempted to implement this because I thought it'd be nice to include the rtl cases by default! I then realized I had to change the labels for rtl so it wasn't using English. Thinking back, this probably could be solved by passing a boolean to the children function for whether or not it is rtl. Here's the commit I tried it in https://github.com/Khan/wonder-blocks/pull/2508/commits/4d233cebd34d8c99eb8157d672a59da2e1b8f970 .

On a related note, I was also wondering if we wanted the `AllVariants` component to cover the hover, focus, press states too in one story instead having one story for each state combination. We could do this by wrapping each table with an id, and then specifying specific selectors when we configure the pseudo states add on:
```
parameters: {
      pseudo: {
          hover: [
              `#${stateElementIds.hover} *`,
              `#${stateElementIds.hoverAndFocus} *`,
          ],
          focusVisible: [
              `#${stateElementIds.focus} *`,
              `#${stateElementIds.hoverAndFocus} *`,
          ],
          active: [`#${stateElementIds.press} *`],
      },
  },
```

While it's possible, I'm not sure if it would be helpful to include it all in one sticker sheet. It would save snapshot amounts though since we'd have ~5 snapshots per component due to the different states!

Curious to hear if anyone has thoughts on this! Happy to iterate on this in another PR :) 
created_at: 2025-03-21T19:33:55Z
author_association: MEMBER
diff_hunk: @@ -89,35 +103,55 @@ export const NavigationTabItem = React.forwardRef(function NavigationTabItem(
     );
 });
 
-const underlineStyles: CSSProperties = {
-    content: '""',
-    display: "block",
-    position: "absolute",
-    bottom: 0,
-    left: 0,
-    right: 0,
-    height: sizing.size_050,
-};
-
 const styles = StyleSheet.create({
     root: {
         listStyle: "none",
         display: "inline-flex",
+        [":has(a:hover)" as any]: {
+            boxShadow: `inset 0 -${sizing.size_050} 0 0 ${semanticColor.action.secondary.progressive.hover.foreground}`,
path: packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx
user: login: beaesguerra
body: Good catch!! Updated the hover underline to be 2px tall. I also made sure the current + hover state remains the same at 4px!
created_at: 2025-03-21T19:34:47Z
author_association: MEMBER
diff_hunk: @@ -31,59 +34,125 @@ type Props = {
      * The states to display in the table as rows.
      */
     columns: Array<Variant>;
+    /**
+     * The layout for AllVariants.
+     * - `responsive`: variants will be displayed in a table at larger screen
+     * sizes and in a list at smaller screen sizes
+     * - `list`: variants will always be displayed in a list
+     */
+    layout?: "responsive" | "list";
 };
 
 /**
  * A table that displays all possible variants of a component.
  */
-export function AllVariants({children, columns, rows}: Props) {
+export function AllVariants(props: Props) {
+    const {children, rows, columns, layout = "responsive"} = props;
+
     return (
-        <StyledTable style={styles.table}>
-            <thead>
-                <tr>
-                    <StyledTh style={styles.cell}>
-                        <LabelLarge>Category / State</LabelLarge>
-                    </StyledTh>
-                    {columns.map((col, index) => (
-                        <StyledTh key={index} scope="col" style={styles.cell}>
-                            <LabelLarge>{col.name}</LabelLarge>
-                        </StyledTh>
-                    ))}
-                </tr>
-            </thead>
-            <tbody>
-                {rows.map((row, idx) => (
-                    <tr key={idx}>
-                        <StyledTh scope="row" style={styles.cell}>
-                            <LabelLarge>{row.name}</LabelLarge>
-                        </StyledTh>
-                        {columns.map((col) => (
-                            <StyledTd
-                                key={col.name}
-                                style={[
-                                    styles.cell,
-                                    {
-                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
-                                    },
-                                ]}
-                            >
-                                {children({
-                                    ...row.props,
-                                    ...col.props,
-                                })}
-                            </StyledTd>
+        <>
+            {layout === "responsive" && (
+                <StyledTable style={[styles.table]}>
+                    <thead>
+                        <tr>
+                            <StyledTh style={styles.cell}>
+                                <LabelLarge>Category / State</LabelLarge>
+                            </StyledTh>
+                            {columns.map((col, index) => (
+                                <StyledTh
+                                    key={index}
+                                    scope="col"
+                                    style={styles.cell}
+                                >
+                                    <LabelLarge>{col.name}</LabelLarge>
+                                </StyledTh>
+                            ))}
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {rows.map((row, idx) => (
+                            <tr key={idx}>
+                                <StyledTh scope="row" style={styles.cell}>
+                                    <LabelLarge>{row.name}</LabelLarge>
+                                </StyledTh>
+                                {columns.map((col) => (
+                                    <StyledTd
+                                        key={col.name}
+                                        style={[
+                                            styles.cell,
+                                            {
+                                                border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+                                            },
+                                        ]}
+                                    >
+                                        {children(
+                                            {
+                                                ...row.props,
+                                                ...col.props,
+                                            },
+                                            `${row.name} ${col.name}`,
path: __docs__/components/all-variants.tsx
user: login: beaesguerra
body: Nice!! I was also addressing a11y warnings in the new stories! I see in #2509 we add `aria-label` to the props. I ended up adding a new argument for the `name` so it could be used for a unique `aria-label`. I was thinking not all components may support an `aria-label` at the root level so providing it as an arg keeps it flexible! What do you think?
created_at: 2025-03-21T19:39:00Z
author_association: MEMBER
diff_hunk: @@ -141,6 +227,58 @@ export const Active: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props, name) => (
+                    <View style={styles.container}>
+                        <NavigationTabs
+                            {...args}
+                            {...props}
+                            aria-label={name}
+                        />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props, name) => (
+                        <View style={styles.container}>
+                            <NavigationTabs
+                                {...args}
+                                {...props}
+                                aria-label={`${name} RTL`}
+                            />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    parameters: {
+        a11y: {
+            config: {
+                rules: [
+                    // Disabling warning: "Element's background color could not
path: __docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx
user: login: beaesguerra
body: It was showing as an incomplete in the Storybook add on! Any tips on how to address this? 

<img width="1725" alt="image" src="https://github.com/user-attachments/assets/40ca2fd1-a78d-48c5-a15b-3fc401da6963" />

I also see it in the labels for the story! Might be related to setting the CSS zoom property?
<img width="1728" alt="image" src="https://github.com/user-attachments/assets/b76c641f-b434-43a7-bb33-b7bbc21b67d8" />


created_at: 2025-03-21T19:46:34Z
author_association: MEMBER
diff_hunk: @@ -31,59 +34,125 @@ type Props = {
      * The states to display in the table as rows.
      */
     columns: Array<Variant>;
+    /**
+     * The layout for AllVariants.
+     * - `responsive`: variants will be displayed in a table at larger screen
+     * sizes and in a list at smaller screen sizes
+     * - `list`: variants will always be displayed in a list
+     */
+    layout?: "responsive" | "list";
 };
 
 /**
  * A table that displays all possible variants of a component.
  */
-export function AllVariants({children, columns, rows}: Props) {
+export function AllVariants(props: Props) {
+    const {children, rows, columns, layout = "responsive"} = props;
+
     return (
-        <StyledTable style={styles.table}>
-            <thead>
-                <tr>
-                    <StyledTh style={styles.cell}>
-                        <LabelLarge>Category / State</LabelLarge>
-                    </StyledTh>
-                    {columns.map((col, index) => (
-                        <StyledTh key={index} scope="col" style={styles.cell}>
-                            <LabelLarge>{col.name}</LabelLarge>
-                        </StyledTh>
-                    ))}
-                </tr>
-            </thead>
-            <tbody>
-                {rows.map((row, idx) => (
-                    <tr key={idx}>
-                        <StyledTh scope="row" style={styles.cell}>
-                            <LabelLarge>{row.name}</LabelLarge>
-                        </StyledTh>
-                        {columns.map((col) => (
-                            <StyledTd
-                                key={col.name}
-                                style={[
-                                    styles.cell,
-                                    {
-                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
-                                    },
-                                ]}
-                            >
-                                {children({
-                                    ...row.props,
-                                    ...col.props,
-                                })}
-                            </StyledTd>
+        <>
+            {layout === "responsive" && (
+                <StyledTable style={[styles.table]}>
+                    <thead>
+                        <tr>
+                            <StyledTh style={styles.cell}>
+                                <LabelLarge>Category / State</LabelLarge>
+                            </StyledTh>
+                            {columns.map((col, index) => (
+                                <StyledTh
+                                    key={index}
+                                    scope="col"
+                                    style={styles.cell}
+                                >
+                                    <LabelLarge>{col.name}</LabelLarge>
+                                </StyledTh>
+                            ))}
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {rows.map((row, idx) => (
+                            <tr key={idx}>
+                                <StyledTh scope="row" style={styles.cell}>
+                                    <LabelLarge>{row.name}</LabelLarge>
+                                </StyledTh>
+                                {columns.map((col) => (
+                                    <StyledTd
+                                        key={col.name}
+                                        style={[
+                                            styles.cell,
+                                            {
+                                                border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+                                            },
+                                        ]}
+                                    >
+                                        {children(
+                                            {
+                                                ...row.props,
+                                                ...col.props,
+                                            },
+                                            `${row.name} ${col.name}`,
+                                        )}
+                                    </StyledTd>
+                                ))}
+                            </tr>
                         ))}
-                    </tr>
-                ))}
-            </tbody>
-        </StyledTable>
+                    </tbody>
+                </StyledTable>
+            )}
+            <StyledUl
+                style={[
+                    styles.list,
+                    layout === "responsive" && styles.listResponsive,
+                ]}
+            >
+                {rows.map((row) => {
+                    return columns.map((column) => {
+                        return (
+                            <li key={`${row.name} ${column.name}`}>
+                                <LabelLarge>
+                                    Column: {column.name}, Row: {row.name}
+                                </LabelLarge>
+
+                                <div
+                                    style={{
+                                        padding: sizing.size_100,
+                                        marginBlock: sizing.size_100,
+                                        border: `${border.width.hairline}px dashed ${semanticColor.border.primary}`,
+                                    }}
+                                >
path: __docs__/components/all-variants.tsx
user: login: beaesguerra
body: Thanks for the reminder! Updated :) 
created_at: 2025-03-21T19:47:14Z
author_association: MEMBER
diff_hunk: @@ -32,8 +32,16 @@ type Props = AriaProps & {
      * tabs.
      */
     "aria-labelledby"?: string;
+    /**
+     * Custom styles for the elements in NavigationTabs.
+     */
+    styles?: {
+        root?: StyleType;
+        list?: StyleType;
path: packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx
user: login: beaesguerra
body: Added more docs!
created_at: 2025-03-21T19:54:42Z
author_association: MEMBER
diff_hunk: @@ -108,3 +115,104 @@ export const ChildrenRenderFunction: StoryComponentType = {
         chromatic: {delay: 500},
     },
 };
+
+/**
+ * Custom styles can be set for the NavigationTabItem.
+ *
+ * For custom link styling, prefer applying the styles to the `Link` component.
+ * Note: The `NavigationTabItem` will also set styles to the `Link` child
+ * component.
+ *
+ * If there is a specific use case where the styling needs to be
+ * overridden, please reach out to the Wonder Blocks team!
+ */
+export const CustomStyle: StoryComponentType = {
path: __docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx
user: login: beaesguerra
body: It is verifying that the style prop works in the visual regression tests (very subtly using spacing 😅). I updated the custom style to have a background color instead so it is more noticable!
created_at: 2025-03-21T19:55:35Z
author_association: MEMBER
diff_hunk: @@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
+            <AllVariants rows={rows} columns={columns}>
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: jandrade
body: oh merging pseudo states would be worth experimenting, and then we could see if there's benefit from that change. how does that sound?
created_at: 2025-03-21T20:07:49Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,42 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    globals: {
+        zoom: "400%",
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because Chromatic crops the story when zoom is used
+            disableSnapshot: true,
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: beaesguerra
body: Thanks for the suggestions! 
- Setting `min-width: 100vw` made it so the NavigationTabs are no longer horizontally scrollable since it allows the container to expand. We want to be able to observe the scrolling behaviour!
- Related to that, I tried setting `width: 100vw` and `maxWidth: 100vw`. The snapshot shows more of the contents, though we lose the horizontal scrolling in the NavigationTabs (it's put on the story instead). [Chromatic snapshot](https://www.chromatic.com/test?appId=5e1bf4b385e3fb0020b7073c&id=67ddc970032bfa82f8d939b1)
- Setting `viewports` didn't work. [Chromatic with viewports config](https://www.chromatic.com/test?appId=5e1bf4b385e3fb0020b7073c&id=67ddc5cc6d557f9e26ef4ba5)
- Setting `defaultViewport` didn't work too (the snapshot was less wide too for some reason) [Chromatic with defaultViewport](https://www.chromatic.com/test?appId=5e1bf4b385e3fb0020b7073c&id=67ddc7f2b3eb368b88187ce4)

I went back to disabling the Zoom stories 😅 I think at least the stories are functional and show the expected behaviour when you try it out in Storybook! One other idea is we could reach out to the Chromatic team to see if they've seen this issue before. (I think it's a Chromatic issue since the story renders as expected and it's only the snapshot that is cropped!). @jandrade how do you normally contact Chromatic for support?
created_at: 2025-03-21T20:37:04Z
author_association: MEMBER
diff_hunk: @@ -96,17 +145,26 @@ const meta = {
     title: "Packages / Tabs / NavigationTabs / NavigationTabItem / NavigationTabItem - All Variants",
     component: NavigationTabItem,
     render: (args) => (
-        <AllVariants rows={rows} columns={columns}>
-            {(props) => (
-                <View style={styles.container}>
-                    <NavigationTabItem {...args} {...props} />
-                </View>
-            )}
-        </AllVariants>
+        <div>
+            <AllVariants rows={rows} columns={columns}>
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: beaesguerra
body: I experimented with merging the pseudo states and rtl in the same story: https://github.com/Khan/wonder-blocks/pull/2511

Left some comments in the draft PR too, feel free to provide feedback in that PR! 
created_at: 2025-03-21T22:41:01Z
author_association: MEMBER
diff_hunk: @@ -143,8 +201,42 @@ export const Press: Story = {
     parameters: {pseudo: {hover: true, active: true}},
 };
 
+export const Zoom: Story = {
+    render: (args) => (
+        <div>
+            <AllVariants rows={rows} columns={columns} layout="list">
+                {(props) => (
+                    <View style={styles.container}>
+                        <NavigationTabItem {...args} {...props} />
+                    </View>
+                )}
+            </AllVariants>
+            <div dir="rtl">
+                <HeadingLarge>RTL</HeadingLarge>
+                <AllVariants rows={rtlRows} columns={columns} layout="list">
+                    {(props) => (
+                        <View style={styles.container}>
+                            <NavigationTabItem {...args} {...props} />
+                        </View>
+                    )}
+                </AllVariants>
+            </div>
+        </div>
+    ),
+    globals: {
+        zoom: "400%",
+    },
+    parameters: {
+        chromatic: {
+            // Disabling because Chromatic crops the story when zoom is used
+            disableSnapshot: true,
path: __docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx
user: login: jandrade
body: That's via their website. You go to the chromatic site, go to the dashboard, then click on the "Chat" button on the bottom right.

https://github.com/user-attachments/assets/7c7166f0-737a-4788-beb5-a97a85eb2923


created_at: 2025-03-25T14:42:17Z
author_association: MEMBER

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-03-20T19:02:50Z
body: ###  🦋  Changeset detected

Latest commit: 9c4fa3dfa67ea7c656bea7695b4f7f1b5c2ccc3d

**The changes in this PR will be included in the next version bump.**

<details><summary>This PR includes changesets to release 1 package</summary>

  | Name                            | Type  |
| ------------------------------- | ----- |
| @khanacademy/wonder-blocks-tabs | Minor |

</details>

Not sure what this means? [Click here  to learn what changesets are](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add another changeset to this PR](https://github.com/Khan/wonder-blocks/new/nav-tabs-style?filename=.changeset/beige-singers-play.md&value=---%0A%22%40khanacademy%2Fwonder-blocks-tabs%22%3A%20patch%0A---%0A%0ANavigationTabs%20Styling%0A)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-20T19:03:49Z
body: **Size Change:** +299 B (+0.3%) 

**Total Size:** 100 kB

| Filename | Size | Change |  |
| :--- | :---: | :---: | :---: |
| `packages/wonder-blocks-tabs/dist/es/index.js` | 1.24 kB | +299 B (+31.67%) | 🚨 |

<details><summary>ℹ️ <strong>View Unchanged</strong></summary>

| Filename | Size |
| :--- | :---: |
| `packages/wonder-blocks-accordion/dist/es/index.js` | 3.54 kB |
| `packages/wonder-blocks-banner/dist/es/index.js` | 1.55 kB |
| `packages/wonder-blocks-birthday-picker/dist/es/index.js` | 1.88 kB |
| `packages/wonder-blocks-breadcrumbs/dist/es/index.js` | 886 B |
| `packages/wonder-blocks-button/dist/es/index.js` | 4.34 kB |
| `packages/wonder-blocks-cell/dist/es/index.js` | 2.35 kB |
| `packages/wonder-blocks-clickable/dist/es/index.js` | 3.07 kB |
| `packages/wonder-blocks-core/dist/es/index.js` | 2.85 kB |
| `packages/wonder-blocks-data/dist/es/index.js` | 6.25 kB |
| `packages/wonder-blocks-dropdown/dist/es/index.js` | 19.5 kB |
| `packages/wonder-blocks-form/dist/es/index.js` | 6.04 kB |
| `packages/wonder-blocks-grid/dist/es/index.js` | 1.36 kB |
| `packages/wonder-blocks-icon-button/dist/es/index.js` | 3.15 kB |
| `packages/wonder-blocks-icon/dist/es/index.js` | 873 B |
| `packages/wonder-blocks-labeled-field/dist/es/index.js` | 1.22 kB |
| `packages/wonder-blocks-layout/dist/es/index.js` | 1.82 kB |
| `packages/wonder-blocks-link/dist/es/index.js` | 2.04 kB |
| `packages/wonder-blocks-modal/dist/es/index.js` | 5.5 kB |
| `packages/wonder-blocks-pill/dist/es/index.js` | 1.49 kB |
| `packages/wonder-blocks-popover/dist/es/index.js` | 4.92 kB |
| `packages/wonder-blocks-progress-spinner/dist/es/index.js` | 1.52 kB |
| `packages/wonder-blocks-search-field/dist/es/index.js` | 1.32 kB |
| `packages/wonder-blocks-switch/dist/es/index.js` | 2.02 kB |
| `packages/wonder-blocks-testing-core/dist/es/index.js` | 3.91 kB |
| `packages/wonder-blocks-testing/dist/es/index.js` | 1.07 kB |
| `packages/wonder-blocks-theming/dist/es/index.js` | 679 B |
| `packages/wonder-blocks-timing/dist/es/index.js` | 1.79 kB |
| `packages/wonder-blocks-tokens/dist/es/index.js` | 2.7 kB |
| `packages/wonder-blocks-toolbar/dist/es/index.js` | 923 B |
| `packages/wonder-blocks-tooltip/dist/es/index.js` | 7.01 kB |
| `packages/wonder-blocks-typography/dist/es/index.js` | 1.23 kB |

</details>



<a href="https://github.com/preactjs/compressed-size-action"><sub>compressed-size-action</sub></a>
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-20T19:06:41Z
body: # A new build was pushed to Chromatic! :rocket:
https://5e1bf4b385e3fb0020b7073c-faxousjuul.chromatic.com/

## Chromatic results:

| Metric | Total |
|---|---|
| Captured snapshots | 404 |
| Tests with visual changes | 0 |
| Total stories | 594 |
| Inherited (not captured) snapshots [TurboSnap] | 0 |
| Tests on the build | 404 |
author_association: CONTRIBUTOR
user: login: khan-actions-bot
created_at: 2025-03-20T21:35:46Z
body: # Gerald

<details>
<summary><b>Required Reviewers</b></summary>

* `@Khan/wonder-blocks` for changes to `.changeset/twenty-actors-tease.md`, `.storybook/preview.tsx`, `__docs__/components/all-variants.tsx`, `__docs__/components/scenarios-layout.tsx`, `__docs__/components/text-for-testing.ts`, `__docs__/wonder-blocks-tabs/navigation-tab-item-variants.stories.tsx`, `__docs__/wonder-blocks-tabs/navigation-tab-item.argtypes.tsx`, `__docs__/wonder-blocks-tabs/navigation-tab-item.stories.tsx`, `__docs__/wonder-blocks-tabs/navigation-tabs-variants.stories.tsx`, `__docs__/wonder-blocks-tabs/navigation-tabs.argtypes.tsx`, `__docs__/wonder-blocks-tabs/navigation-tabs.stories.tsx`, `packages/wonder-blocks-tabs/src/components/navigation-tab-item.tsx`, `packages/wonder-blocks-tabs/src/components/navigation-tabs.tsx`
</details>


__________________________________________________________________________________________________________________________________
_Don't want to be involved in this pull request? Comment `#removeme` and we won't notify you of further changes._
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-20T21:36:31Z
body: ## npm Snapshot: Published
🎉 Good news!! We've packaged up the latest commit from this PR (cac8b315) and published all packages with changesets to npm.

You can install the packages in webapp by running:
```sh
./services/static/dev/tools/deploy_wonder_blocks.js --tag="PR2508"
```

Packages can also be installed manually by running:
```sh
pnpm add @khanacademy/wonder-blocks-<package-name>@PR2508
```
author_association: CONTRIBUTOR
user: login: codecov[bot]
created_at: 2025-03-25T15:19:37Z
body: ## [Codecov](https://app.codecov.io/gh/Khan/wonder-blocks/pull/2508?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 0.00%. Comparing base [(`dcd7532`)](https://app.codecov.io/gh/Khan/wonder-blocks/commit/dcd7532ec627417102c8efe978ac713ec65cd7bb?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan) to head [(`9c4fa3d`)](https://app.codecov.io/gh/Khan/wonder-blocks/commit/9c4fa3dfa67ea7c656bea7695b4f7f1b5c2ccc3d?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan).
> Report is 1 commits behind head on feature/tabs.

<details><summary>Additional details and impacted files</summary>


[![Impacted file tree graph](https://app.codecov.io/gh/Khan/wonder-blocks/pull/2508/graphs/tree.svg?width=650&height=150&src=pr&token=ny8PAxdjV4&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan)](https://app.codecov.io/gh/Khan/wonder-blocks/pull/2508?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan)

```diff
@@         Coverage Diff          @@
##   feature/tabs   #2508   +/-   ##
====================================
====================================

```

------

[Continue to review full report in Codecov by Sentry](https://app.codecov.io/gh/Khan/wonder-blocks/pull/2508?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://app.codecov.io/gh/Khan/wonder-blocks/pull/2508?dropdown=coverage&src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan). Last update [dcd7532...9c4fa3d](https://app.codecov.io/gh/Khan/wonder-blocks/pull/2508?dropdown=coverage&src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Khan).

</details>
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE