13.1.0 • Published 10 months ago

@leafygreen-ui/tabs v13.1.0

Weekly downloads
397
License
Apache-2.0
Repository
github
Last release
10 months ago

Tabs

npm (scoped)

View on MongoDB.design

Installation

Yarn

yarn add @leafygreen-ui/tabs

NPM

npm install @leafygreen-ui/tabs

Example

import { Tabs, Tab } from '@leafygreen-ui/tabs';

const [selected, setSelected] = useState(0)

<Tabs setSelected={setSelected} selected={selected}>
  <Tab name="Tab One">Tab Content One</Tab>
  <Tab name="Tab Two">Tab Content Two</Tab>
  <Tab name="Tab Three">Tab Content Three</Tab>
</Tabs>

Properties

PropTypeDescriptionDefault
selected'number' | 'string'Index or name of the Tab that should appear active. If using the name, pass the text content from the Tab name prop. If selected is undefined, the <Tabs /> component will behave as an uncontrolled component. If selected is passed a string or number that cannot be found, nothing will be selected.
setSelectedfunctionA callback that receives the index or name of the tab a user is switching to when clicking, or via keyboard navigation. Usually this is used to set the selected prop to the correct index or name. The function is only invoked if the selected prop is set.
asReact.ElementTypeSets the root element of all <Tab /> components in <Tabs />. For example, setting as to Link will render each tab as a <Link /> component rather than as a button.button
classNamestringAdds a className to the root element.
childrennode<Tab /> components that will be supplied to <Tabs /> component.
darkModebooleanDetermines whether or not the component will appear in DarkModefalse
baseFontSize13 | 16Determines font-size for Tabs Component13
size'small' | 'default'Determines size for Tabs Component'default'

Any other properties supplied will be spread on the root element.

Tab

Properties

PropTypeDescriptionDefault
name (Required)string, ReactNodeString that will appear in the list of tabs.
disabledbooleanIndicates whether or not the <Tab /> can be clicked by a user.false
defaultbooleanShould be supplied when using the uncontrolled <Tabs /> component. This determines which tab will be active by default.
classNamestringAdds a className to the root element.
hrefstringDestination when Tab's name in the list should be rendered as an a tag.
tostringDestination when Tab's name in the list should be rendered as a Link tag.
childrennodeContent that appears inside the <Tab /> component
...native attributes of component passed to as propAny other props will be spread on the root element

Test Harnesses

getTestUtils()

getTestUtils() is a util that allows consumers to reliably interact with LG Tabs in a product test suite. If the Tabs component cannot be found, an error will be thrown.

Usage

import { getTestUtils } from '@leafygreen-ui/tabs';

const utils = getTestUtils(lgId?: string); // lgId refers to the custom `data-lgid` attribute passed to `Tabs`. It defaults to 'lg-tabs' if left empty.

Single Tabs component

import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Tabs, Tab, getTestUtils } from '@leafygreen-ui/tabs';

...

test('tabs', () => {
  render(
    <Tabs aria-label="Label">
      <Tab name="First" default>
        Content 1
      </Tab>
      <Tab name="Second">
        Content 2
      </Tab>
      <Tab name="Third">
        Content 3
      </Tab>
    </Tabs>
  );

  const { getAllTabPanelsInDOM, getAllTabsInTabList, getSelectedPanel, getTabUtilsByName } = getTestUtils();

  expect(getAllTabsInTabList()).toHaveLength(3);
  expect(getAllTabPanelsInDOM()).toHaveLength(1);

  const firstTabUtils = getTabUtilsByName('First');
  expect(firstTabUtils.isSelected()).toBeTruthy();

  expect(getSelectedPanel()).toHaveTextContent('Content 1');

  const secondTabUtils = getTabUtilsByName('Second');

  // click to second tab
  if (secondTabUtils) {
    userEvent.click(secondTabUtils.getTab());
  }
  // selected panel text content is updated
  expect(getSelectedPanel()).toHaveTextContent('Content 2');
});

Multiple Tabs components

When testing multiple Tabs components, it is recommended to add the custom data-lgid attribute to each Tabs.

import { render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Tabs, Tab, getTestUtils } from '@leafygreen-ui/tabs';

...

test('tabs', () => {
  render(
    <>
      <Tabs aria-label="Label ABC" data-lgid="tabs-abc">
        <Tab name="A" default>
          Content A
        </Tab>
        <Tab name="B">
          Content B
        </Tab>
        <Tab name="C">
          Content C
        </Tab>
      </Tabs>
      <Tabs aria-label="Label XY" data-lgid="tabs-xy" forceRenderAllTabPanels={true}>
        <Tab name="X">
          Content X
        </Tab>
        <Tab name="Y" default>
          Content Y
        </Tab>
      </Tabs>
    </>
  );

  const testUtils1 = getTestUtils('tabs-abc'); // data-lgid
  const testUtils2 = getTestUtils('tabs-xy'); // data-lgid

  // First tabs
  expect(testUtils1.getAllTabsInTabList()).toHaveLength(3);
  expect(testUtils1.getAllTabPanelsInDOM()).toHaveLength(1);
  expect(testUtils1.getSelectedPanel()).toHaveTextContent('Content A');

  // Second tabs
  expect(testUtils2.getAllTabsInTabList()).toHaveLength(2);
  expect(testUtils2.getAllTabPanelsInDOM()).toHaveLength(2);
  expect(testUtils2.getSelectedPanel()).toHaveTextContent('Content Y');
});

Test Utils

const {
  getAllTabPanelsInDOM,
  getAllTabsInTabList,
  getTabUtilsByName: { getTab, isSelected, isDisabled },
  getSelectedPanel,
} = getTestUtils();
UtilDescriptionReturns
getAllTabPanelsInDOM()Returns an array of tab panelsArray<HTMLElement>
getAllTabsInTabList()Returns an array of tabsArray<HTMLElement>
getSelectedPanel()Returns the selected tab panelHTMLElement | null
getTabUtilsByName()Returns tab utils if tab with matching name is foundTabUtils | null
TabUtils
getTab()Returns the tabHTMLElement
isSelected()Returns whether the tab is selectedboolean
isDisabled()Returns whether the tab is disabledboolean

Reference

Usage with NextJS Link components

Tabs may not render with the correct tags or styles if the NextJS Link component is passed to the as prop directly, given how NextJS handles default rendering of the component based on the href prop. To work around this, pass the NextJS Link as shown below.

import NextLink from 'next/link';

function Linker({ href, children, ...props }) {
  return (
    <NextLink href={href}>
      <a {...props}>
        {children}
      </a>
    </NextLink>
  );
}

<Tabs aria-label="Profile Sections" as={Linker}>
...
</Tabs>
13.1.0

10 months ago

12.0.3

12 months ago

12.0.0

1 year ago

12.0.1

1 year ago

12.0.2

1 year ago

13.0.0

11 months ago

13.0.1

11 months ago

11.2.0

1 year ago

11.1.15

1 year ago

11.1.14

1 year ago

11.1.11

2 years ago

11.1.10

2 years ago

11.1.13

2 years ago

11.1.12

2 years ago

12.0.0-alpha.1

2 years ago

12.0.0-alpha.0

2 years ago

11.1.5

2 years ago

11.1.6

2 years ago

11.1.4

2 years ago

11.1.9

2 years ago

11.1.7

2 years ago

11.1.8

2 years ago

11.0.10

2 years ago

11.1.1-next.5

2 years ago

11.1.1-next.4

2 years ago

11.1.1-next.7

2 years ago

11.1.1-next.6

2 years ago

11.0.9

2 years ago

11.1.1-next.1

2 years ago

11.1.1-next.0

2 years ago

11.1.1-next.3

2 years ago

11.1.1-next.2

2 years ago

11.1.3

2 years ago

11.1.1

2 years ago

11.1.2

2 years ago

11.1.0

2 years ago

11.0.6

2 years ago

11.0.7

2 years ago

11.0.5

2 years ago

11.0.8

2 years ago

11.0.4

2 years ago

11.0.2

3 years ago

11.0.3

2 years ago

11.0.0

3 years ago

11.0.1

3 years ago

9.2.1

3 years ago

10.0.0

3 years ago

10.0.1

3 years ago

9.1.0

3 years ago

9.2.0

3 years ago

9.1.0-test.0

3 years ago

9.1.0-next.2

3 years ago

9.1.0-next.0

3 years ago

9.1.0-next.1

3 years ago

9.0.2

3 years ago

9.0.1

3 years ago

8.0.0

3 years ago

9.0.0

3 years ago

7.0.1

3 years ago

6.0.3

3 years ago

6.0.2

3 years ago

7.0.0

3 years ago

6.0.1

3 years ago

6.0.0

3 years ago

5.1.5

4 years ago

5.1.4

4 years ago

5.1.3

4 years ago

5.1.2

4 years ago

5.1.1

4 years ago

5.1.0

4 years ago

5.0.3

4 years ago

5.0.2

4 years ago

5.0.1

4 years ago

5.0.0

4 years ago

4.0.6

4 years ago

4.0.5

5 years ago

4.0.4

5 years ago

4.0.3

5 years ago

4.0.2

5 years ago

4.0.1

5 years ago

4.0.0

5 years ago

3.0.1

5 years ago

3.0.0

5 years ago

2.1.6

5 years ago

2.1.5

5 years ago

2.1.4

5 years ago

2.1.3

5 years ago

2.1.2

5 years ago

2.1.1

5 years ago

2.1.0

5 years ago

2.0.1

5 years ago

2.0.0

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago