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.

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 tabbar 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',
}