Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(TabPanel): Added tabStop boolean prop to TabPanel #2413

Merged
merged 8 commits into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions packages/components/src/Tabs/TabPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,22 @@ import styled from 'styled-components'
export interface TabPanelProps {
className?: string
selected?: boolean
/**
* Set to `true` if you would like TabPanel to be reached via tab-key.
* Generally this is _only_ the case when the TabPanel contains no tab-stopping items (a, button, etc.)
* @default false
*/
isTabStop?: boolean
}

const TabPanelLayout: FC<TabPanelProps> = ({ children, className, selected }) =>
const TabPanelLayout: FC<TabPanelProps> = ({
children,
className,
selected,
isTabStop = false,
}) =>
selected ? (
<div className={className} tabIndex={0}>
<div className={className} tabIndex={isTabStop ? 0 : -1}>
{children}
</div>
) : null
Expand Down
49 changes: 49 additions & 0 deletions packages/components/src/Tabs/Tabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import '@testing-library/jest-dom/extend-expect'
import { renderWithTheme } from '@looker/components-test-utils'
import React from 'react'
import { fireEvent, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Tab } from './Tab'
import { TabList } from './TabList'
import { TabPanel } from './TabPanel'
Expand Down Expand Up @@ -197,6 +198,54 @@ describe('focus behavior', () => {
)
})

test('Tab Focus: By default, TabPanel is not tabbable', () => {
renderWithTheme(
<Tabs>
<TabList>
<Tab>tab1</Tab>
<Tab>tab2</Tab>
</TabList>
<TabPanels>
<TabPanel>
<button>Some button</button>
</TabPanel>
<TabPanel>this is tab2 content</TabPanel>
</TabPanels>
</Tabs>
)
userEvent.tab()
expect(screen.getByText('tab1')).toHaveFocus()

userEvent.tab()
expect(screen.getByText('Some button')).toHaveFocus()
})

test('Tab Focus: TabPanel can use "isTabStop" prop to become tabbable element', () => {
renderWithTheme(
<Tabs>
<TabList>
<Tab>tab1</Tab>
<Tab>tab2</Tab>
</TabList>
<TabPanels>
<TabPanel isTabStop>
<button>Some button</button>
</TabPanel>
<TabPanel>this is tab2 content</TabPanel>
</TabPanels>
</Tabs>
)
userEvent.tab()
expect(screen.getByText('tab1')).toHaveFocus()

const button = screen.getByText('Some button')
userEvent.tab()
expect(button.closest('div'))

userEvent.tab()
expect(button).toHaveFocus()
})

test('Tab keyboard navigation', () => {
renderWithTheme(<TabTest />)
const tab1 = screen.getByText('tab1')
Expand Down
23 changes: 23 additions & 0 deletions www/src/documentation/components/content/tabs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,26 @@ Using the distribute prop on `TabList` will equally distributed each `Tab` in th
)
}
```

## Keyboard Navigation

When focused on a `Tab`, use the left and right arrow keys to navigate to sibling `Tab`s.

By default, `TabPanel` is not reachable via the "Tab" key. If you'd like `TabPanel` to be reachable via the "Tab" key, set the `isTabStop` prop to `true`.

```jsx
;() => {
return (
<Tabs>
<TabList>
<Tab>isTabStop = true</Tab>
<Tab>isTabStop = false (Default)</Tab>
</TabList>
<TabPanels>
<TabPanel isTabStop>I'm reachable by pressing the tab key</TabPanel>
<TabPanel>I'm not reachable by pressing the tab key</TabPanel>
</TabPanels>
</Tabs>
)
}
```