Skip to content

Import

import { Tabs } from '@dnb/eufemia'

Description

Tabs are a set of buttons that allow navigation between content that is related and on the same level of hierarchy.

Relevant links

Demos

Tabs where content is provided from outside

As this may be a more common use case, we still have to ensure our tabs content is linked together with the tabs – because of accessibility.

You have to provide an id to both of the components.

NB: You don't need to use a function inside Tabs.Content – it can contain any element you need, as long as it is a React Node.

one

Code Editor
<Tabs
  id="unique-linked-id"
  data={[
    {
      title: 'One',
      key: 'one',
    },
    {
      title: 'Two',
      key: 'two',
    },
  ]}
/>
<Tabs.Content id="unique-linked-id" key="unique-linked-key">
  {({ key }) => {
    return <H2>{key}</H2>
  }}
</Tabs.Content>

Tabs using 'data' property and content object

First

Code Editor
<Tabs
  data={[
    {
      title: 'First',
      key: 'first',
    },
    {
      title: 'Second',
      key: 'second',
    },
    {
      title: 'Third',
      key: 'third',
      disabled: true,
    },
    {
      title: 'Fourth',
      key: 'fourth',
    },
  ]}
>
  {exampleContent /* See Example Content below */}
</Tabs>

Tabs using 'data' property only

First

Code Editor
<Tabs
  data={{
    first: {
      title: 'First',
      // See Example Content below
      content: exampleContent.first,
    },
    second: {
      title: 'Second',
      // See Example Content below
      content: exampleContent.second,
    },
  }}
  // Only use "on_click" if you really have to
  on_click={({ selected_key }) => {
    console.log('on_click', selected_key)
  }}
  // Preferred way to listen on changes
  on_change={({ selected_key }) => {
    console.log('on_change', selected_key)
  }}
/>

Tabs using React Components only

Also, this is an example of how to define a different content background color, by providing content_style.

Code Editor
<Tabs tabs_style="info" content_style="info">
  <Tabs.Content title="First" key="first">
    <Section spacing top bottom style_type="white">
      <H2 top={0} bottom>
        First
      </H2>
    </Section>
  </Tabs.Content>
  <Tabs.Content title="Second" key="second">
    <Section spacing top bottom style_type="white">
      <H2 top={0} bottom>
        Second
      </H2>
    </Section>
  </Tabs.Content>
</Tabs>

Tabs without bottom border

First

Code Editor
<Tabs no_border={true}>
  <Tabs.Content title="First" key="first">
    <H2 top={0} bottom>
      First
    </H2>
  </Tabs.Content>
  <Tabs.Content title="Second" key="second">
    <H2 top={0} bottom>
      Second
    </H2>
  </Tabs.Content>
</Tabs>

Tabs without breakout

First

Code Editor
<Tabs breakout={false}>
  <Tabs.Content title="First" key="first">
    <H2 top={0} bottom>
      First
    </H2>
  </Tabs.Content>
  <Tabs.Content title="Second" key="second">
    <H2 top={0} bottom>
      Second
    </H2>
  </Tabs.Content>
</Tabs>

Tabs and prerender

By using prerender={true} the content is kept inside the DOM.

Also, when switching the tabs, the height is animated.

Smile at me 📸

Code Editor
<>
  <Tabs prerender content_style="info">
    <Tabs.Content title="Tab 1" key="first">
      <H2>Content 1</H2>
    </Tabs.Content>
    <Tabs.Content title="Tab 2" key="second">
      <div
        style={{
          height: '10rem',
          display: 'flex',
          alignItems: 'flex-end',
        }}
      >
        <H2>Content 2</H2>
      </div>
    </Tabs.Content>
    <Tabs.Content title="Tab 3" key="third">
      <div
        style={{
          height: '20rem',
          display: 'flex',
          alignItems: 'flex-end',
        }}
      >
        <H2>Content 3</H2>
      </div>
    </Tabs.Content>
  </Tabs>
  <P top>Smile at me 📸</P>
</>

Tabs optimized for narrow screens

Navigation buttons will be shown and the tabs-list will be scrollable.

Second
Code Editor
<Tabs selected_key="second" data={manyTabs}>
  {manyTabsContent}
</Tabs>

Horizontal aligned tabs

Code Editor
const FlexWrapper = styled.div`
  display: flex;
  flex-direction: row;
`
const LeftArea = styled.div`
  /* Ensure no-wrap */
  flex-shrink: 0;
`
const RightArea = styled.div`
  /* Ensure the tab bar is hidden outside this area */
  overflow: hidden;

  /* Ensure the focus ring is visible! (because of overflow: hidden) */
  margin: -2px;
  padding: 2px;
`
function TabsHorizontalAligned() {
  return (
    <FlexWrapper>
      <LeftArea>
        <ToggleButton.Group value="first">
          <ToggleButton text="first" value="first" />
          <ToggleButton text="second" value="second" />
        </ToggleButton.Group>
      </LeftArea>

      <RightArea>
        <Tabs
          left
          no_border
          selected_key="first"
          id="unique-tabs-row"
          data={manyTabs}
        />
      </RightArea>
    </FlexWrapper>
  )
}
render(<TabsHorizontalAligned />)

max-width usage

Code Editor
const MaxWidthWrapper = styled.div`
  max-width: 30rem;
  background: var(--color-white);
`
function TabsMaxWidth() {
  return (
    <MaxWidthWrapper>
      <Tabs
        top
        no_border
        selected_key="fifth"
        id="unique-tabs-max-width"
        data={manyTabs}
      />
    </MaxWidthWrapper>
  )
}
render(<TabsMaxWidth />)

Router integration

This demo uses @reach/router. More examples on CodeSandbox.

Example Content

const exampleContent = {
first: () => <H2>First</H2>,
second: () => <Input label="Label:">Focus me with next Tab key</Input>,
third: () => (
<>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</>
),
fourth: 'Fourth as a string only',
}