diff --git a/README.md b/README.md index 24da281962..701b012360 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ https://reactcommunity.org/react-tabs/ > Supports React 16.8.0 or newer

react-tabs was tested on real mobile devices and browsers with
- Browserstack +Browserstack

@@ -16,7 +16,9 @@ https://reactcommunity.org/react-tabs/ ```bash yarn add react-tabs ``` + or + ```bash npm install --save react-tabs ``` @@ -78,7 +80,7 @@ react-tabs consists of 4 components which all need to be used together. If you specify additional props on the `` component they will be forwarded to the rendered `
`. -#### className: `string | Array | { [string]: boolean }` +#### className: `string | Array | { [string]: boolean }` > default: `"react-tabs"` @@ -130,6 +132,14 @@ Register a callback that will receive the underlying DOM node for every mount. I If you're rendering `react-tabs` within a different `window` context than the default one; for example, an iframe. +#### focusTabOnClick: `boolean` + +> default: `true` + +By default the tab that is clicked will also be focused in the DOM. If set to `false` the tab will not be focused anymore. + +> Be aware that keyboard navigation will not work after click if set to false. Though one can still focus the tabs by pressing `tab` and then keyboard navigation will work. + #### forceRenderTabPanel: `boolean` > default: `false` @@ -178,7 +188,7 @@ Provide a custom class name for the active tab panel. If you specify additional props on the `` component they will be forwarded to the rendered `
    `. -#### className: `string | Array | { [string]: boolean }` +#### className: `string | Array | { [string]: boolean }` > default: `"react-tabs__tab-list"` @@ -190,7 +200,7 @@ Provide a custom class name for the `
      `. If you specify additional props on the `` component they will be forwarded to the rendered `
    • `. -#### className: `string | Array | { [string]: boolean }` +#### className: `string | Array | { [string]: boolean }` > default: `"react-tabs__tab"` @@ -230,7 +240,7 @@ Overrides the tabIndex to enabled tabbing between tabs. If you specify additional props on the `` component they will be forwarded to the rendered `
      `. -#### className: `string | Array | { [string]: boolean }` +#### className: `string | Array | { [string]: boolean }` > default: `"react-tabs__tab-panel"` @@ -265,7 +275,7 @@ This is the default mode of react-tabs and makes the react-tabs components handl In this mode you cannot force a tab change during runtime. ```js - console.log(index)}> + console.log(index)}> Title 1 Title 2 @@ -288,7 +298,7 @@ const App = () => { const [tabIndex, setTabIndex] = useState(0); return ( - setTabIndex(index)}> + setTabIndex(index)}> Title 1 Title 2 @@ -340,13 +350,15 @@ When using the UMD version of react-tabs you can easily use the default styles b ... - + ... ``` - ### Custom Style You can also always just simply copy the default style to your own css/scss/less and modify it to your own needs. The changelog will always tell you when classes change and we also consider changes that break the styling as semver major. @@ -354,19 +366,20 @@ You can also always just simply copy the default style to your own css/scss/less ### Custom Components #### Set `tabsRole` + In case you want to create your own component wrapping the ones that the library provides, you have to set its `tabsRole`. This value is used inside react-tabs to check the role of a component inside ``. Possible values for tabsRole are: - * Tab - * TabPanel - * TabList -#### Pass through properties -Note: Because of how react-tabs works internally (it uses cloning to opaquely control various parts of the tab state), you need to pass any incoming props to the component you're wrapping. The easiest way to do this is to use the rest and spread operators, e.g. see `{...otherProps}` below. +- Tab +- TabPanel +- TabList +#### Pass through properties +Note: Because of how react-tabs works internally (it uses cloning to opaquely control various parts of the tab state), you need to pass any incoming props to the component you're wrapping. The easiest way to do this is to use the rest and spread operators, e.g. see `{...otherProps}` below. -``` javascript +```javascript import { Tabs, TabList, Tab, TabPanel } from 'react-tabs'; // All custom elements should pass through other props diff --git a/src/components/Tabs.js b/src/components/Tabs.js index 5416b14488..9978e52d69 100644 --- a/src/components/Tabs.js +++ b/src/components/Tabs.js @@ -23,6 +23,7 @@ const propTypes = { disabledTabClassName: PropTypes.string, disableUpDownKeys: PropTypes.bool, domRef: PropTypes.func, + focusTabOnClick: PropTypes.bool, forceRenderTabPanel: PropTypes.bool, onSelect: onSelectPropType, selectedIndex: selectedIndexPropType, @@ -32,6 +33,7 @@ const propTypes = { }; const defaultProps = { defaultFocus: false, + focusTabOnClick: true, forceRenderTabPanel: false, selectedIndex: null, defaultIndex: null, @@ -64,7 +66,8 @@ For more information about controlled and uncontrolled mode of react-tabs see ht * It is initialized from the prop defaultFocus, and after the first render it is reset back to false. Later it can become true again when using keys to navigate the tabs. */ const Tabs = (props) => { - const { children, defaultFocus, defaultIndex, onSelect } = props; + const { children, defaultFocus, defaultIndex, focusTabOnClick, onSelect } = + props; const [focus, setFocus] = useState(defaultFocus); const [mode] = useState(getModeFromProps(props)); @@ -97,8 +100,10 @@ const Tabs = (props) => { if (onSelect(index, last, event) === false) return; } - // Always set focus on tabs - setFocus(true); + // Always set focus on tabs unless it is disabled + if (focusTabOnClick) { + setFocus(true); + } if (mode === MODE_UNCONTROLLED) { // Update selected index @@ -116,6 +121,7 @@ const Tabs = (props) => { } delete subProps.defaultFocus; delete subProps.defaultIndex; + delete subProps.focusTabOnClick; return {children}; }; diff --git a/src/components/__tests__/Tabs-test.js b/src/components/__tests__/Tabs-test.js index 4dedaec614..9fe0adc59f 100644 --- a/src/components/__tests__/Tabs-test.js +++ b/src/components/__tests__/Tabs-test.js @@ -594,6 +594,21 @@ describe('', () => { assertTabSelected(1); }); + test('should not focus tabs if focusTabOnClick is false', () => { + render(createTabs({ focusTabOnClick: false })); + const firstTab = screen.getByTestId('tab1'); + const secondTab = screen.getByTestId('tab2'); + + expect(firstTab).not.toHaveFocus(); + expect(secondTab).not.toHaveFocus(); + assertTabSelected(1); + + userEvent.click(secondTab); + expect(firstTab).not.toHaveFocus(); + expect(secondTab).not.toHaveFocus(); + assertTabSelected(2); + }); + test('should not change tabs when arrow up/down is pressed and disableUpDownKeys is passed', () => { render( createTabs({