diff --git a/README.md b/README.md index 816cb8a10..c73ca980d 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,12 @@ Provide a custom class name for disabled tabs. > This option can also be set directly at the `` component. +#### disableUpDownKeys: `bool` + +> default: `false` + +Disable up & down arrow keys to change tabs. + #### domRef: `(node: ?HTMLElement) => void` > default: `null` diff --git a/src/components/Tabs.js b/src/components/Tabs.js index bbc2a4115..b3e6fdadb 100644 --- a/src/components/Tabs.js +++ b/src/components/Tabs.js @@ -18,6 +18,7 @@ export default class Tabs extends Component { selectedIndex: null, defaultIndex: null, environment: null, + disableUpDownKeys: false, }; static propTypes = { @@ -31,6 +32,7 @@ export default class Tabs extends Component { defaultFocus: PropTypes.bool, defaultIndex: PropTypes.number, disabledTabClassName: PropTypes.string, + disableUpDownKeys: PropTypes.bool, domRef: PropTypes.func, forceRenderTabPanel: PropTypes.bool, onSelect: onSelectPropType, diff --git a/src/components/UncontrolledTabs.js b/src/components/UncontrolledTabs.js index eb7fdef0a..4933a1f53 100644 --- a/src/components/UncontrolledTabs.js +++ b/src/components/UncontrolledTabs.js @@ -56,6 +56,7 @@ export default class UncontrolledTabs extends Component { PropTypes.object, ]), disabledTabClassName: PropTypes.string, + disableUpDownKeys: PropTypes.bool, domRef: PropTypes.func, focus: PropTypes.bool, forceRenderTabPanel: PropTypes.bool, @@ -259,7 +260,7 @@ export default class UncontrolledTabs extends Component { } handleKeyDown = (e) => { - const { direction } = this.props; + const { direction, disableUpDownKeys } = this.props; if (this.isTabFromContainer(e.target)) { let { selectedIndex: index } = this.props; let preventDefault = false; @@ -271,8 +272,8 @@ export default class UncontrolledTabs extends Component { this.handleClick(e); } - if (e.keyCode === 37 || e.keyCode === 38) { - // Select next tab to the left + if (e.keyCode === 37 || (!disableUpDownKeys && e.keyCode === 38)) { + // Select next tab to the left, validate if up arrow is not disabled if (direction === 'rtl') { index = this.getNextTab(index); } else { @@ -280,8 +281,8 @@ export default class UncontrolledTabs extends Component { } preventDefault = true; useSelectedIndex = true; - } else if (e.keyCode === 39 || e.keyCode === 40) { - // Select next tab to the right + } else if (e.keyCode === 39 || (!disableUpDownKeys && e.keyCode === 40)) { + // Select next tab to the right, validate if down arrow is not disabled if (direction === 'rtl') { index = this.getPrevTab(index); } else { @@ -368,6 +369,7 @@ export default class UncontrolledTabs extends Component { selectedTabClassName, // unused selectedTabPanelClassName, // unused environment, // unused + disableUpDownKeys, // unused ...attributes } = this.props; diff --git a/src/components/__tests__/Tabs-test.js b/src/components/__tests__/Tabs-test.js index c6d78d3fb..1b7173777 100644 --- a/src/components/__tests__/Tabs-test.js +++ b/src/components/__tests__/Tabs-test.js @@ -502,4 +502,43 @@ describe('', () => { , ); }); + + test('should change tabs when arrow up/down is pressed', () => { + render(createTabs()); + const firstTab = screen.getByTestId('tab1'); + const secondTab = screen.getByTestId('tab2'); + + userEvent.tab(); + expect(firstTab).toHaveFocus(); + assertTabSelected(1); + + userEvent.type(firstTab, '{arrowdown}'); + expect(secondTab).toHaveFocus(); + assertTabSelected(2); + + userEvent.type(secondTab, '{arrowup}'); + expect(firstTab).toHaveFocus(); + assertTabSelected(1); + }); + + test('should not change tabs when arrow up/down is pressed and disableUpDownKeys is passed', () => { + render( + createTabs({ + disableUpDownKeys: true, + }), + ); + const firstTab = screen.getByTestId('tab1'); + + userEvent.tab(); + expect(firstTab).toHaveFocus(); + assertTabSelected(1); + + userEvent.type(firstTab, '{arrowdown}'); + expect(firstTab).toHaveFocus(); + assertTabSelected(1); + + userEvent.type(firstTab, '{arrowup}'); + expect(firstTab).toHaveFocus(); + assertTabSelected(1); + }); });