Menu Close

Mantine Responsive Tabs

I’ve been using Mantine for one of my side projects and came across this easy way to use the Theme hooks to help responsiveness.

Lets say you are using something like Tabs and you want to have a vertical layout on a larger screen and a horizontal layout in a smaller screen. Unfortunately, the Tab orientation is set with a component prop, so, as far as I know, there’s no way to toggle the orientation using the Styles API. There are two tools we can use together to set the initial orientation, based on the viewport (“screen”) size and the defined breakpoints. Here’s the code:

import { Paper, Tabs, useMantineTheme } from '@mantine/core';
import { useViewportSize } from '@mantine/hooks';

export default function ResponsiveTabs() {
  const { width } = useViewportSize(); // height is also available here
  const theme = useMantineTheme();
  const breakpoint = Boolean(width >= theme.breakpoints.md);
  const padX = breakpoint ? 10 : 0;
  const padY = breakpoint ? 0 : 10;
  return (
    <Tabs
      variant="outline"
      orientation={breakpoint ? 'vertical' : 'horizontal'}
      defaultValue="start"
    >
      <Tabs.List>
        <Tabs.Tab value="start">
          First Tab
        </Tabs.Tab>
        <Tabs.Tab value="middle">
          Second Tab
        </Tabs.Tab>
        <Tabs.Tab value="end">
          Last Tab
        </Tabs.Tab>
      </Tabs.List>
      <Tabs.Panel value="start">
        <Paper px={padX} py={padY}>
          First tab content
        </Paper>
      </Tabs.Panel>
      <Tabs.Panel value="middle">
        <Paper px={padX} py={padY}>
          Second tab content
        </Paper>
      </Tabs.Panel>
      <Tabs.Panel value="end">
        <Paper px={padX} py={padY}>
          Last tab content
        </Paper>
      </Tabs.Panel>
    </Tabs>
  );
}

What’s going on here?

We use the useViewportSize() hook to get the viewport (screen) width:

const { width } = useViewportSize();

We then use the useMantineTheme() hook to set the theme object, which provides us with the theme’s defined breakpoints. The width and the breakpoints are both numbers, so we can easily compare a specific breakpoint width to the current viewport width.

const theme = useMantineTheme();   
const breakpoint = Boolean(width >= theme.breakpoints.md);

I chose the Medium breakpoint for this example, but you could use sm (small) or even lg (large) if desired. Now we need to conditionally set the Tab orientation:

<Tabs
  variant="outline"
  orientation={breakpoint ? 'vertical' : 'horizontal'}
  defaultValue="start"
>

The above will set the Tab orientation to vertical if the screen size is the same as md (medium) or larger. If the screen size is sm (small) or smaller, then the Tab orientation will be horizontal.

If you are using the Styles API, you could easily adjust other styling, but for simplicity I decided to use the same condition to set padding. For vertical Tabs, some padding on the sides is more appealing. For horizontal Tabs, I prefer some padding on the top and bottom.

<Tabs.Panel value="middle">
  <Paper px={breakpoint ? 10 : 0} py={breakpoint ? 0 : 10}>
    Second tab content

This prevents creating another dependency, which is basically adding no further benefit. If you are already using the createStyles() hook, then it makes more sense to put it in a class instead. I have no further need for createStyles(), so I just put each padding type in constants in the original code example.

So that’s it, that’s how you can use the Theme object to add responsiveness to Mantine Tabs or any other component limited in the Styles API. This method also doesn’t limit the responsiveness to the initial viewport size, like it may in other frameworks. If you are on a larger screen and resize the window, it should swap orientation as it crosses the medium breakpoint.

Posted in WebDev

Related Posts