{}} />)
+ expect(screen.getByText('14')).toBeInTheDocument()
+ })
+
+ it('calls onChange with tab value', async () => {
+ const onChange = vi.fn()
+ const user = userEvent.setup()
+ render()
+ await user.click(screen.getByText('Routes'))
+ expect(onChange).toHaveBeenCalledWith('routes')
+ })
+})
diff --git a/src/design-system/composites/Tabs/Tabs.tsx b/src/design-system/composites/Tabs/Tabs.tsx
new file mode 100644
index 0000000..284e8b7
--- /dev/null
+++ b/src/design-system/composites/Tabs/Tabs.tsx
@@ -0,0 +1,36 @@
+import styles from './Tabs.module.css'
+
+interface TabItem {
+ label: string
+ count?: number
+ value: string
+}
+
+interface TabsProps {
+ tabs: TabItem[]
+ active: string
+ onChange: (value: string) => void
+ className?: string
+}
+
+export function Tabs({ tabs, active, onChange, className }: TabsProps) {
+ return (
+
+ {tabs.map((tab) => (
+
+ ))}
+
+ )
+}