frontend/src/stories/How to add tabs to a scene.stories.mdx
import { Meta } from '@storybook/addon-docs'
<Meta title="How to add tabs to a scene?" />This guide follows on from "How to build a scene" – we'll be adding tabs to that guide's Dashboards scene.
frontend/src/types.ts to define the tabs:export enum DashboardsTabs {
First = 'first',
Second = 'second',
}
frontend/src/scenes/urls.ts to handle tabs:dashboards: (tab: DashboardsTabs = DashboardsTabs.First): string => `/dashboards/${tab}`
frontend/src/scenes/scenes.ts: // One entry for every available tab
...Object.fromEntries(
Object.values(DashboardsTabs).map((tab) => [urls.dashboards(tab), Scene.Dashboards])
) as Record<string, Scene>,
dashboardsLogic to handle tab changes in frontend/src/scenes/dashboards/dashboardsLogic.ts:import { actions, kea, path, reducers, selectors } from 'kea'
import { actionToUrl, urlToAction } from 'kea-router'
import { urls } from 'scenes/urls'
import { Breadcrumb, DashboardsTabs } from '~/types'
export const DASHBOARDS_TAB_TO_NAME: Record<DashboardsTabs, string> = {
[DashboardsTabs.First]: 'First',
[DashboardsTabs.Second]: 'Second',
}
export const dashboardsLogic = kea([
path(['scenes', 'dashboard', 'dashboardsLogic']),
actions({
setCurrentTab: (tab: DashboardsTabs = DashboardsTabs.First) => ({ tab }),
}),
reducers({
currentTab: [
DashboardsTabs.First as DashboardsTabs,
{
setCurrentTab: (_, { tab }) => tab,
},
],
}),
selectors(() => ({
breadcrumbs: [
// Optional if you'd like the breadcrumbs to show the current tab
(s) => [s.currentTab],
(tab): Breadcrumb[] => {
const breadcrumbs: Breadcrumb[] = [{ name: 'Dashboards' }]
breadcrumbs.push({
name: DASHBOARDS_TAB_TO_NAME[tab],
})
return breadcrumbs
},
],
})),
actionToUrl(({ values }) => {
return {
setCurrentTab: () => [urls.dashboards(values.currentTab)],
}
}),
urlToAction(({ actions, values }) => ({
'/dashboards/:tab': ({ tab }) => {
if (tab !== values.currentTab) {
actions.setCurrentTab(tab as DashboardsTabs)
}
},
})),
])
frontend/src/scenes/dashboards/Dashboards.tsx to render the tabs:import { useValues } from 'kea'
import { router } from 'kea-router'
import { LemonTabs } from 'lib/lemon-ui/LemonTabs/LemonTabs'
import { SceneExport } from 'scenes/sceneTypes'
import { urls } from 'scenes/urls'
import { DashboardsTabs } from '~/types'
import { dashboardsLogic, humanFriendlyTabName } from './dashboardsLogic'
const DASHBOARDS_TAB_TO_CONTENT: Record<DashboardsTabs, JSX.Element> = {
[DashboardsTabs.First]: <div>First tab content</div>,
[DashboardsTabs.Second]: <div>Second tab content</div>,
}
export const scene: SceneExport = {
component: Dashboards,
logic: dashboardsLogic,
}
export function Dashboards(): JSX.Element {
const { currentTab } = useValues(dashboardsLogic)
return (
<div>
<LemonTabs
activeKey={currentTab}
onChange={(tab) => router.actions.push(urls.dashboards(tab as DashboardsTabs))}
tabs={Object.values(DashboardsTabs).map((tab) => ({
label: DASHBOARDS_TAB_TO_NAME[tab],
key: tab,
content: DASHBOARDS_TAB_TO_CONTENT[tab],
}))}
/>
</div>
)
}