diff --git a/.changeset/tabpanel-classname.md b/.changeset/tabpanel-classname.md new file mode 100644 index 0000000..86793b0 --- /dev/null +++ b/.changeset/tabpanel-classname.md @@ -0,0 +1,5 @@ +--- +"@qorpe/ui": minor +--- + +`TabPanel` accepts `className` (defaults to the previous `pt-4`): a scrolling panel inside a flex column can now carry `min-h-0 flex-1 overflow-y-auto` and its own padding without losing the ARIA pairing — the seam mockifyr's five tabbed screens need to move off their local Radix tabs. diff --git a/src/components/TabStrip.test.tsx b/src/components/TabStrip.test.tsx index 60c07e7..47bf2e2 100644 --- a/src/components/TabStrip.test.tsx +++ b/src/components/TabStrip.test.tsx @@ -94,4 +94,23 @@ describe("TabStrip", () => { // meaning on its own. expect(screen.getByRole("tab", { name: /Jobs/ })).toBeInTheDocument(); }); + + it("a panel carries its own layout classes when given, and the default padding when not", () => { + const { rerender } = render( + + body + , + ); + expect(screen.getByRole("tabpanel")).toHaveClass("pt-4"); + rerender( + + body + , + ); + const panel = screen.getByRole("tabpanel"); + expect(panel).toHaveClass("min-h-0", "flex-1", "overflow-y-auto"); + expect(panel).not.toHaveClass("pt-4"); + // The ARIA pairing survives the class swap. + expect(panel).toHaveAttribute("aria-labelledby", "tab-s-a"); + }); }); diff --git a/src/components/TabStrip.tsx b/src/components/TabStrip.tsx index 669ed93..5e5cbdb 100644 --- a/src/components/TabStrip.tsx +++ b/src/components/TabStrip.tsx @@ -80,16 +80,23 @@ export interface TabPanelProps { children: React.ReactNode; /** Must match the strip's `scope` — the two halves pair through the prefixed ids (B7). */ scope?: string; + /** + * The panel's layout classes — a scrolling panel inside a flex column needs + * `min-h-0 flex-1 overflow-y-auto` and its own padding. Defaults to the strip's + * `pt-4`; passing a value REPLACES it (the ARIA pairing is untouched). Added for the + * family's second consumer, whose five tabbed screens are scroll layouts (2026-09-05). + */ + className?: string; } /** The panel half of the pattern — labelled by its tab, hidden when it is not the one. */ -export function TabPanel({ id, activeId, children, scope }: TabPanelProps) { +export function TabPanel({ id, activeId, children, scope, className = "pt-4" }: TabPanelProps) { if (id !== activeId) { return null; } return ( -
+
{children}
);