{"id":16369117,"url":"https://github.com/rhys-vdw/react-context-tabs","last_synced_at":"2025-03-23T02:33:52.017Z","repository":{"id":123583138,"uuid":"65978894","full_name":"rhys-vdw/react-context-tabs","owner":"rhys-vdw","description":"Flexible tabs for React","archived":false,"fork":false,"pushed_at":"2019-04-01T05:23:23.000Z","size":73,"stargazers_count":30,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-18T16:56:11.862Z","etag":null,"topics":["context","react","tab","tabs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rhys-vdw.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-08-18T08:19:09.000Z","updated_at":"2024-08-22T10:00:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"f8ba66d1-5fa7-4a98-be1e-b1284f26977c","html_url":"https://github.com/rhys-vdw/react-context-tabs","commit_stats":null,"previous_names":["usabilityhub/react-context-tabs"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhys-vdw%2Freact-context-tabs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhys-vdw%2Freact-context-tabs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhys-vdw%2Freact-context-tabs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhys-vdw%2Freact-context-tabs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhys-vdw","download_url":"https://codeload.github.com/rhys-vdw/react-context-tabs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245048012,"owners_count":20552431,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["context","react","tab","tabs"],"created_at":"2024-10-11T02:54:37.574Z","updated_at":"2025-03-23T02:33:52.006Z","avatar_url":"https://github.com/rhys-vdw.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# React context tabs\n\n[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)\n\nA flexible and unopinionated tab interface for React. Tabs and panes to be provided in any order or nesting. Inactive panels can be either unmounted or just hidden from view. Includes an optional minimal base stylesheet, but leaves aesthetics up to you.\n\n## Table of Contents\n- [Install](#install)\n- [Usage](#usage)\n - [Basic example](#basic-example)\n - [Controlled tabs](#controlled-tabs)\n - [Nesting](#nesting)\n- [Styles](#styles)\n- [API](#api)\n - [`Tabs`](#tabs)\n - [`TabList`](#tablist)\n - [`Tab`](#tab)\n - [`TabPanel`](#tabpanel)\n - [`PersistentTabPanel`](#persistenttabpanel)\n- [Contribute](#contribute)\n- [License](#license)\n\n## Install\n\n```console\nnpm install react-context-tabs --save\n```\n\n## Usage\n\n### Basic example\n\nStraight forward tabs!\n\n```jsx\nimport React from 'react'\nimport { Tab, TabList, Tabs, TabPanel } from 'react-context-tabs'\n\nexport default function TabExample() {\n  return (\n    \u003cTabs defaultTabId='home'\u003e\n      \u003cTabList\u003e\n        \u003cTab tabId='home'\u003eReact context tabs\u003c/Tab\u003e\n        \u003cTab tabId='about'\u003eWhat is it?\u003c/Tab\u003e\n        \u003cTab tabId='issues'\u003eI have a problem\u003c/Tab\u003e\n      \u003c/TabList\u003e\n      \u003cTabPanel tabId='home'\u003e\n        \u003cp\u003e\n          Flexible tabs for React\n        \u003c/p\u003e\n      \u003c/TabPanel\u003e\n      \u003cTabPanel tabId='about'\u003e\n        \u003cp\u003e\n          A fine React library\n        \u003c/p\u003e\n      \u003c/TabPanel\u003e\n      \u003cTabPanel tabId='issues'\u003e\n        \u003cp\u003e\n          Problem? Try our\n          \u003ca href=\"https://github.com/usabilityhub/react-context-tabs/issues\"\u003eissues\u003c/a\u003e page.\n        \u003c/p\u003e\n      \u003c/TabPanel\u003e\n    \u003c/Tabs\u003e\n  )\n}\n```\n\n### Controlled tabs\n\n`Tabs` can be either \"[controlled](https://facebook.github.io/react/docs/forms.html#controlled-components)\" or \"[uncontrolled](https://facebook.github.io/react/docs/forms.html#uncontrolled-components)\". Controlled tabs require a `selectedTabId` property.\n\n```jsx\nimport React, { Component } from 'react'\nimport { Tab, TabList, Tabs, TabPanel } from 'react-context-tabs'\n\nfunction getHash() {\n  return window.location.hash.slice(1)\n}\n\nclass HashControlledTabs extends Component {\n\n  constructor(props) {\n    super(props)\n    this.state = { selectedTabId: getHash() }\n    this.handleHashChange = this.handleHashChange.bind(this)\n    this.handleTabChange = this.handleTabChange.bind(this)\n  }\n\n  componentDidMount() {\n    window.onhashchange = this.handleHashChange\n  }\n\n  componentWillUnmount() {\n    window.onhashchange = null\n  }\n\n  handleHashChange(event) {\n    this.setState({ selectedTabId: getHash() })\n  }\n\n  handleTabChange(nextTab, prevTab) {\n    window.location.hash = nextTab\n  }\n\n  render() {\n    const { selectedTabId } = this.state\n\n    return (\n      \u003cTabs\n        selectedTabId={selectedTabId}\n        onTabChange={this.handleTabChange}\n      \u003e\n        \u003cTabList\u003e\n          \u003cTab tabId='happy'\u003eHappy\u003c/Tab\u003e\n          \u003cTab tabId='sad'\u003eSad\u003c/Tab\u003e\n        \u003c/TabList\u003e\n        \u003cTabPanel tabId='happy'\u003e\n          \u003cspan style={{ fontSize: '100px', transform: 'rotate(0.25turn)' }}\u003e\n            :)\n          \u003c/span\u003e\n        \u003c/TabPanel\u003e\n        \u003cTabPanel tabId='sad'\u003e\n          \u003cspan style={{ fontSize: '100px', transform: 'rotate(0.25turn)' }}\u003e\n            :(\n          \u003c/span\u003e\n        \u003c/TabPanel\u003e\n      \u003c/Tabs\u003e\n    )\n  }\n}\n\n```\n\n### Nesting\n\nThanks to React's [context](https://facebook.github.io/react/docs/context.html) feature, children can be re-ordered or nested as you please.\n\n```jsx\nimport React from 'react'\nimport { Tab, TabList, Tabs, TabPanel } from 'react-context-tabs'\n\nfunction CharacterInformation({ warrior, wizard }) {\n  return (\n    \u003cTabs defaultTabId='warrior'\u003e\n\n      \u003csection className='characterInfo'\u003e\n        \u003cTabPanel tabId='warrior'\u003e\n          \u003cCharacterStats stats={warrior.stats} /\u003e\n        \u003c/TabPanel\u003e\n        \u003cTabPanel tabId='wizard'\u003e\n\n          {/* Tabception */}\n          \u003cTabs defaultTabId='stats'\u003e\n            \u003cTabList\u003e\n              \u003cTab tabId='stats'\u003eStats\u003c/Tab\u003e\n              \u003cTab tabId='spells'\u003eSpells\u003c/Tab\u003e\n            \u003c/TabList\u003e\n            \u003cTabPanel tabId='stats'\u003e\n              \u003cCharacterStats stats={wizard.stats} /\u003e\n            \u003c/TabPanel\u003e\n            \u003cTabPanel tabId='spells'\u003e\n              \u003cCharacterSpells spells={wizard.spells} /\u003e\n            \u003c/TabPanel\u003e\n          \u003c/Tabs\u003e\n\n        \u003c/TabPanel\u003e\n      \u003c/section\u003e\n\n      {/* Children can be any old component */}\n      \u003cmarquee\u003eSelect your character!\u003c/marquee\u003e\n\n      {/* Tabs come after panels */}\n      \u003csection className='characterSelection'\u003e\n        \u003cTabList\u003e\n          \u003cTab tabId='warrior'\u003e\n            Warrior\n          \u003c/Tab\u003e\n          \u003cTab tabId='wizard'\u003e\n            Wizard\n          \u003c/Tab\u003e\n        \u003c/TabList\u003e\n      \u003c/section\u003e\n    \u003c/Tabs\u003e\n  )\n}\n```\n\n## Styles\n\nA base style sheet is included in the build at [`/lib/styles/base.css`](src/styles/base.css). This just sets appropriate cursor and removes default list styles (for the `TabList`). You'll still need to write your own CSS to make the tabs look how you want.\n\nEach component has a default class name that is the same as its component name. eg:\n\n```html\n\u003cdiv class=\"Tabs\"\u003e\n  \u003cul class=\"TabList\"\u003e\n    \u003cli class=\"Tab isSelected\"\u003eFirst\u003c/li\u003e\n    \u003cli class=\"Tab\"\u003eSecond\u003c/li\u003e\n  \u003c/ul\u003e\n  \u003csection className=\"TabPanel\"\u003e\n    First content\n  \u003c/section\u003e\n\u003c!--\n  \u003csection className=\"TabPanel\"\u003e\n    Second content\n  \u003c/section\u003e\n--\u003e\n\u003c/div\u003e\n```\n\n_Note that `PersistentTabPanel` and `TabPanel` both have the same class: `TabPanel`._\n\n## API\n\n### `Tabs`\n\nParent container to which child components are passed. `Tabs` can be either \"[controlled](https://facebook.github.io/react/docs/forms.html#controlled-components)\" or \"[uncontrolled](https://facebook.github.io/react/docs/forms.html#uncontrolled-components)\". Supply either `defaultTabId` for uncontrolled or `selectedTabId` for controlled.\n\n```js\nimport { Tabs } from 'react-context-tabs'\nimport Tabs from 'react-context-tabs/Tabs'\n```\n\n```jsx\n// controlled\n\u003cTabs\n  selectedTabId={this.state.selectedTabId}\n  onTabChange={(nextTabId, prevTabId) =\u003e\n    this.setState({ selectedTadId: nextTabId })\n  }\n\u003e\n  {/* ... */}\n\u003c/Tabs\u003e\n\n// uncontrolled\n\u003cTabs defaultTabId={initialTabId}\u003e\n  {/* ... */}\n\u003c/Tabs\u003e\n```\n\n#### Props\n- `defaultTabId`: `any` - The `tabId` of the initially selected tab when uncontrolled.\n- `selectedTabId`: `any` - The `tabId` of the currently selected tab when controlled.\n- `onTabChange`: `(nextTabId, prevTabId) =\u003e` - Called when the tab changes. Optional for uncontrolled tabs.\n\n### `TabList`\n\nA wrapper component for `Tab`s. This is just a `ul`.\n\n```js\nimport { TabList } from 'react-context-tabs'\nimport TabList from 'react-context-tabs/TabList'\n```\n\n```jsx\n\u003cTabList\u003e\n  \u003cTab tabId='inbox'\u003eInbox\u003c/Tab\u003e\n  \u003cTab tabId='outbox'\u003eOutbox\u003c/Tab\u003e\n  \u003cTab tabId='sent'\u003eSent\u003c/Tab\u003e\n\u003c/TabList\u003e\n```\n\n### `Tab`\n\nAn individual tab. Has CSS class `Tab`, and `isSelected` or `isDisabled`.\n\n```js\nimport { Tab } from 'react-context-tabs'\nimport Tab from 'react-context-tabs/Tab'\n```\n\n```jsx\n\u003cTab tabId='home'\u003e\n  \u003cIcon icon='house' /\u003e\n  Home\n\u003c/Tab\u003e\n```\n\n#### Props\n- `tabId`: `any` - The ID of the `TabPanel` to show when clicked.\n- `disabled`: `bool` - Disallow clicking on this tab.\n- `tabindex`: `number` - Allow this tab to be selected with \u003ckbd\u003etab\u003c/kbd\u003e. See [MDN `tabindex` reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex).\n\n### `TabPanel`\n\nContainer for each tab's content. `TabPanel`s are removed from the DOM when inactive.\n\n`TabPanel` can be used as children of a [`ReactCSSTransitionGroup`](https://facebook.github.io/react/docs/animation.html#high-level-api-reactcsstransitiongroup).\n\n```js\nimport { TabPanel } from 'react-context-tabs'\nimport TabPanel from 'react-context-tabs/TabPanel'\n```\n\n```jsx\n\u003cTabPanel tabId='avatar'\u003e\n  \u003cimg src={`/images/avatars/${user.id}.jpeg`} /\u003e\n  \u003cspan\u003e{ user.name }\u003c/span\u003e\n\u003c/TabPanel\u003e\n```\n\n#### Props\n- `tabId`: `any` - The ID of the `Tab` that will reveal this panel.\n\n### `PersistentTabPanel`\n\nAn alternative to `TabPanel`. `PersistentTabPanel` is *not* removed from the DOM when inactive. Instead it is set to `display: none`. Children will not be rendered until the tab is first revealed.\n\nThese panels are useful for tabs that are computationally expensive to render, or need to persist internal state while deselected.\n\n```js\nimport { PersistentTabPanel } from 'react-context-tabs'\nimport PersistentTabPanel from 'react-context-tabs/PersistentTabPanel'\n```\n\n#### Props\n- `tabId`: `any` - The ID of the `Tab` that will reveal this panel.\n\n## Contribute\n\nQuestions, bug reports and pull requests welcome. See [GitHub issues](https://github.com/usabilityhub/react-context-tabs/issues).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhys-vdw%2Freact-context-tabs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhys-vdw%2Freact-context-tabs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhys-vdw%2Freact-context-tabs/lists"}