Tabs allow you to organize content across different screens, data sets, and
other interactions. The @react-md/tabs
package provides a bunch of components
to help create accessible tabs, but here's a list of the most important
components:
TabsManager
- The main wrapper component for all the Tabs
. You must
provide a tabsId
, a list of tab configuration, and optional settings for
your tabs. You'll need to ensure that this component is a parent of all the
next components.
Tabs
- This component will render all the tabs from the TabsManager
component ensuring correct keyboard accessibility and updating tabs to be
active when needed.
TabPanels
- This component is a wrapper for the TabPanel
component that
manages switching out the active TabPanel
as needed and animating these
panels in and out of view. It will also reset scrolling when the tab has
changed. The children
for this component must be the TabPanel
component without any conditional rendering. This component will clone in
the required id
and aria-*
props into the child TabPanel
that is active.
TabPanel
- The final component that creates an accessible tabpanel
widget
that links to a Tab
within the Tabs
component with the aria-labelledby
attribute.
The Tabs
component will also allow the user to navigate through tabs with the
left and right arrow keys and optionally auto-select the tabs. Check out the
demos below to see example usage and explanations for the TabPanels
/TabPanel
components.
As stated above, you'll want to use the TabsManager
, Tabs
, TabPanels
, and
TabPanel
components to render your general tab layout. For each tab within the
tabs
list, you'll need to have a matching TabPanel
in the TabsPanel
component.
Even though you'll normally use the tab components together, you don't
actually need to use them all within the same component. You can move the Tabs
into a custom header with the AppBar
or even move the content into separate
components to render complex data. The only requirement still is that the
TabPanels
must only have children of TabPanel
.
Check out the example below for separated components as well as adding icons to the tabs.
One of the downsides about the default behavior for tabs is that when a tab is
not currently active, it will be removed from the DOM. This means that if your
component fetches data or has local state, it will be reset once the tab becomes
inactive. This means that if you want to maintain state between the tabs, you'll
need to move the state up above the TabPanels
component and pass it down to
your panels instead.
Since this isn't always ideal, you can also enable the persistent
flag which
will always render all the tab panels and apply the hidden
attribute for
inactive tabs so they can't be tab focusable.
Unlike most of the components within react-md
, tabs actually done have their
own theme. This is really because tabs are generally rendered in AppBar
s or
inline with other content on the page. If you want to apply your own theme, it's
as simple as adding a background-color
and optionally updating the indicator's
background color of the primary
theme color is not visible on the new
background.
This example below will allow you to configure the tabs with a few different
options as well as show how you can define your own custom theme and updating
the indicator color with rmd-tabs-theme-update-var
mixin.
Creating swipeable tabs are not build into the library at this point since swipe
behavior is pretty opinionated and hard to add a reasonable default. That being
said, you can use a library like
react-swipeable along with
the @react-md/tabs
package to get your desired swipe behavior.
To add swiping, you'll want to control the activeIndex
state for the
TabsManager
by providing an activeIndex
prop and onActiveIndexChange
callback prop. The onActiveIndexChange
is required so that when a tab is
clicked or keyboard navigated and clicked, the activeIndex
will automatically
be updated as expected.
From here, you'll want to update the TabPanels
to be persisent
so that you
can apply a transform
style to the active tab and the next tab that should
become visible. While the user is swiping, you'll also want to enable the
disableTransition
prop so that once the swipe is completed, the tab updates
immediately instead of possibly re-animating the entire swiped distance again.
Finally, you'll want to create a custom SwipeablePanel
that accepts all the
TabPanel
props along with:
When the user starts swiping, you'll manually add a style
object to the
current active panel along with the panel that is being swiped towards with a
transform: translateX(${distance})
as well as removing the hidden
prop for
the panel.
Check out the example below that also works for "mouse swiping". The example code also has some comments about where things might need to be improved and other oddities.