--- type: ai-agent-documentation version: 2.0 component: TabSelector status: stable audience: ai-coding-agents-only human-readable: false category: navigation framework-support: - vanilla: true - react: true - vue: true - angular: true - svelte: true --- # Component: TabSelector DEFINITION: The TabSelector component provides accessible, keyboard-navigable tabbed interfaces to organize content. It relies on a specific HTML structure and is activated by a JavaScript class. ## Installation ```bash npm install @pm7/core ``` ### CSS & JavaScript Import REQUIRED: Import both the CSS and the main JavaScript file. ```javascript // ES modules import '@pm7/core/dist/pm7.css'; import '@pm7/core'; // Imports and initializes all components // HTML ``` ## Required Structure The component requires a container with `data-pm7-tab-selector`, a `.pm7-tab-list` for triggers, and corresponding `.pm7-tab-content` panels. The link between a trigger and a panel is made with `aria-controls` and `id`. ```html

Content for Panel 1

Content for Panel 2

``` ### Structural Rules - **ALWAYS**: The main container MUST have `data-pm7-tab-selector`. - **ALWAYS**: A `
...
...
``` ### Pattern: Programmatic Tab Selection ```javascript const element = document.querySelector('[data-pm7-tab-selector]'); const instance = element.PM7TabSelector; // Select the third tab (index 2) instance.selectTabByIndex(2); // Select the tab that controls the panel with id="security-panel" instance.selectTabById('security-panel'); ``` ## Anti-Patterns ### NEVER: Mismatch `aria-controls` and `id` ```html
...
The JavaScript cannot link the button to the panel, and the tab will not switch.
...
``` ### NEVER: Use `onClick` handlers for switching ```javascript // NEVER document.querySelector('[aria-controls="panel-2"]').addEventListener('click', () => { // manual DOM manipulation to show panel 2 }); // BECAUSE --> This bypasses the component's built-in logic, breaking keyboard navigation, accessibility attributes, and state management. // INSTEAD --> // Let the component handle it, or use the provided API. instance.selectTabById('panel-2'); ``` ## React Integration > **📚 Framework Integration Guide**: For Vue, Angular, and other framework integrations, see the comprehensive [Framework Integration Guide](https://raw.githubusercontent.com/patrickmast/pm7-ui/main/README-Framework-Integration.md) ### State Management in React PM7-UI TabSelector can be used as either controlled or uncontrolled component in React: ### Uncontrolled TabSelector (Let PM7 Manage State) ```jsx function TabsExample() { useEffect(() => { window.PM7?.initFramework(); }, []); return (

Overview Content

This is the overview tab content.

Features Content

This is the features tab content.

Pricing Content

This is the pricing tab content.

); } ``` ### Controlled TabSelector (React Manages State) ```jsx function ControlledTabs() { const [activeTab, setActiveTab] = useState(0); useEffect(() => { window.PM7?.initFramework(); // Listen for PM7 tab change events const handleTabChange = (e) => { setActiveTab(e.detail.index); }; document.addEventListener('pm7:tab:change', handleTabChange); return () => document.removeEventListener('pm7:tab:change', handleTabChange); }, []); const handleTabClick = (index) => { // Update React state setActiveTab(index); // Also update PM7 TabSelector const tabSelector = document.querySelector('[data-pm7-tab-selector]')?.PM7TabSelector; if (tabSelector) { tabSelector.selectTabByIndex(index); } }; return (

Active Tab: {activeTab}

{['Overview', 'Features', 'Pricing'].map((label, index) => ( ))}
{['Overview Content', 'Features Content', 'Pricing Content'].map((content, index) => (

{content}

This is the content for tab {index + 1}.

))}
); } ``` ### Dynamic Tabs with React ```jsx function DynamicTabs({ tabs }) { const [activeTab, setActiveTab] = useState(0); useEffect(() => { // Re-initialize PM7 when tabs change window.PM7?.init(); }, [tabs]); useEffect(() => { const handleTabChange = (e) => { setActiveTab(e.detail.index); }; document.addEventListener('pm7:tab:change', handleTabChange); return () => document.removeEventListener('pm7:tab:change', handleTabChange); }, []); return (
{tabs.map((tab, index) => ( ))}
{tabs.map((tab, index) => (
{tab.content}
))}
); } ``` ### Tab Navigation with URL State ```jsx function TabsWithRouting() { const [searchParams, setSearchParams] = useSearchParams(); const activeTab = searchParams.get('tab') || 'overview'; useEffect(() => { window.PM7?.initFramework(); // Select tab based on URL const tabIndex = ['overview', 'features', 'pricing'].indexOf(activeTab); if (tabIndex >= 0) { const tabSelector = document.querySelector('[data-pm7-tab-selector]')?.PM7TabSelector; tabSelector?.selectTabByIndex(tabIndex); } }, [activeTab]); useEffect(() => { const handleTabChange = (e) => { const tabLabels = ['overview', 'features', 'pricing']; setSearchParams({ tab: tabLabels[e.detail.index] }); }; document.addEventListener('pm7:tab:change', handleTabChange); return () => document.removeEventListener('pm7:tab:change', handleTabChange); }, [setSearchParams]); return (
{/* Tab content */}
); } ``` ### Key Points for React: - TabSelector can work as both controlled and uncontrolled component - Use `pm7:tab:change` event to sync with React state - Call `PM7.init()` when dynamically adding tabs - Let PM7 handle the `aria-selected` and `data-state` updates - For controlled components, update both React state and PM7 instance ## Rules ### ALWAYS - **ALWAYS**: Ensure every `pm7-tab-trigger` has an `aria-controls` attribute that exactly matches the `id` of a `pm7-tab-content` element. - **ALWAYS**: Use `

Profile Settings

Notification Settings

Security Settings

```