-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: Support textfields and other interactive components in Gridlists #10195
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
base: main
Are you sure you want to change the base?
Changes from all commits
27eae61
5ab7678
9227d33
d1ccfa6
cc8e6b1
158d3ce
e66db0b
f350944
e872ea8
7a88537
c1343f9
ebe6f6a
8a4e0b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -672,7 +672,7 @@ function Example(props) { | |
|
|
||
| Use the `layout` and `orientation` props to arrange items in horizontal and vertical stacks and grids. This affects keyboard navigation and drag and drop behavior. | ||
|
|
||
| ```tsx render docs={docs.exports.GridList} links={docs.links} props={['layout', 'orientation', 'keyboardNavigationBehavior']} initialProps={{layout: 'grid', orientation: 'horizontal', keyboardNavigationBehavior: 'tab'}} wide | ||
| ```tsx render docs={docs.exports.GridList} links={docs.links} props={['layout', 'orientation']} initialProps={{layout: 'grid', orientation: 'horizontal'}} wide | ||
| "use client"; | ||
| import {GridList, GridListItem, Text} from 'vanilla-starter/GridList'; | ||
|
|
||
|
|
@@ -704,6 +704,56 @@ let photos = [ | |
| </GridList> | ||
| ``` | ||
|
|
||
| ## Keyboard navigation | ||
|
|
||
| By default, GridList uses arrow key navigation to move focus into rows. Set `keyboardNavigationBehavior="tab"` to have <Keyboard>Tab</Keyboard> move focus in and out of a row. | ||
| Use this when rows contain interactive elements such as text fields, where arrow keys and typing in the field should not trigger grid navigation or selection. | ||
|
|
||
| ```tsx render | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps not the most realistic example... maybe we can think about it |
||
| "use client"; | ||
| import {GridList, GridListItem, Text} from 'vanilla-starter/GridList'; | ||
| import {ComboBox, ComboBoxItem} from 'vanilla-starter/ComboBox'; | ||
|
|
||
| ///- begin collapse -/// | ||
| ///- begin collapse -/// | ||
| let photos = [ | ||
| {id: 1, title: 'Desert Sunset', description: 'PNG • 2/3/2024', src: 'https://images.unsplash.com/photo-1705034598432-1694e203cdf3?q=80&w=600&auto=format&fit=crop'}, | ||
| {id: 2, title: 'Hiking Trail', description: 'JPEG • 1/10/2022', src: 'https://images.unsplash.com/photo-1722233987129-61dc344db8b6?q=80&w=600&auto=format&fit=crop'}, | ||
| {id: 3, title: 'Lion', description: 'JPEG • 8/28/2021', src: 'https://images.unsplash.com/photo-1629812456605-4a044aa38fbc?q=80&w=600&auto=format&fit=crop'}, | ||
| {id: 4, title: 'Mountain Sunrise', description: 'PNG • 3/15/2015', src: 'https://images.unsplash.com/photo-1722172118908-1a97c312ce8c?q=80&w=600&auto=format&fit=crop'}, | ||
| {id: 5, title: 'Giraffe tongue', description: 'PNG • 11/27/2019', src: 'https://images.unsplash.com/photo-1574870111867-089730e5a72b?q=80&w=600&auto=format&fit=crop'}, | ||
| {id: 6, title: 'Golden Hour', description: 'WEBP • 7/24/2024', src: 'https://images.unsplash.com/photo-1718378037953-ab21bf2cf771?q=80&w=600&auto=format&fit=crop'}, | ||
| ]; | ||
|
|
||
| function PermissionPicker({label}) { | ||
| return ( | ||
| <ComboBox style={{paddingInlineStart: 12, width: '80%'}} aria-label={label} defaultSelectedKey="view" placeholder="Permission"> | ||
| <ComboBoxItem id="view">Can view</ComboBoxItem> | ||
| <ComboBoxItem id="comment">Can comment</ComboBoxItem> | ||
| <ComboBoxItem id="edit">Can edit</ComboBoxItem> | ||
| </ComboBox> | ||
| ); | ||
| } | ||
| ///- end collapse -/// | ||
|
|
||
| <GridList | ||
| /*- begin highlight -*/ | ||
| keyboardNavigationBehavior="tab" | ||
| /*- end highlight -*/ | ||
| items={photos} | ||
| selectionMode="multiple" | ||
| aria-label="Shared files"> | ||
| {item => ( | ||
| <GridListItem textValue={item.title}> | ||
| <img src={item.src} alt="" /> | ||
| <Text>{item.title}</Text> | ||
| <Text slot="description">{item.description}</Text> | ||
| <PermissionPicker label={`${item.title} permission`} /> | ||
| </GridListItem> | ||
| )} | ||
| </GridList> | ||
| ``` | ||
|
|
||
| ## Drag and drop | ||
|
|
||
| GridList supports drag and drop interactions when the `dragAndDropHooks` prop is provided using the <TypeLink links={docs.links} type={docs.exports.useDragAndDrop} /> hook. Users can drop data on the list as a whole, on individual items, insert new items between existing ones, or reorder items. React Aria supports drag and drop via mouse, touch, keyboard, and screen reader interactions. See the [drag and drop guide](dnd?component=GridList) to learn more. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -257,7 +257,7 @@ import {Tree, TreeHeader, TreeItem, TreeSection} from 'vanilla-starter/Tree'; | |
| <TreeItem id="shared-photos" title="Shared Photos"> | ||
| <TreeItem id="shared-photo-1" title="Shared Photo 1" /> | ||
| <TreeItem id="shared-photo-2" title="Shared Photo 2" /> | ||
| </TreeItem> | ||
| </TreeItem> | ||
| </TreeSection> | ||
| <TreeSection> | ||
| <TreeHeader>Documents</TreeHeader> | ||
|
|
@@ -322,6 +322,61 @@ function Example(props) { | |
| } | ||
| ``` | ||
|
|
||
| ## Keyboard navigation | ||
|
|
||
| By default, Tree uses arrow key navigation to move focus into rows. Set `keyboardNavigationBehavior="tab"` to have <Keyboard>Option</Keyboard> move focus in and out of a row. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this should be Tab rather than Option? But make this description match whatever we end up with for GridList. |
||
| Use this when rows contain interactive elements such as text fields, where arrow keys and typing in the field should not trigger grid navigation or selection. | ||
|
|
||
| ```tsx render | ||
| "use client"; | ||
| import {Tree, TreeItem, TreeItemContent} from 'vanilla-starter/Tree'; | ||
| import {ComboBox, ComboBoxItem} from 'vanilla-starter/ComboBox'; | ||
|
|
||
| ///- begin collapse -/// | ||
| function PermissionPicker({label}) { | ||
| return ( | ||
| <ComboBox style={{marginInlineStart: 'auto', flexShrink: 0}} aria-label={label} defaultSelectedKey="view" placeholder="Permission"> | ||
| <ComboBoxItem id="view">Can view</ComboBoxItem> | ||
| <ComboBoxItem id="comment">Can comment</ComboBoxItem> | ||
| <ComboBoxItem id="edit">Can edit</ComboBoxItem> | ||
| </ComboBox> | ||
| ); | ||
| } | ||
| ///- end collapse -/// | ||
|
|
||
| <Tree | ||
| /*- begin highlight -*/ | ||
| keyboardNavigationBehavior="tab" | ||
| /*- end highlight -*/ | ||
| selectionMode="multiple" | ||
| defaultExpandedKeys={['documents', 'photos']} | ||
| aria-label="Shared files" | ||
| style={{width: 420}}> | ||
| <TreeItem id="documents" title="Documents"> | ||
| <TreeItem id="weekly" textValue="Weekly Report.pdf"> | ||
| <TreeItemContent> | ||
| Weekly Report.pdf | ||
| <PermissionPicker label="Weekly Report.pdf permission" /> | ||
| </TreeItemContent> | ||
| </TreeItem> | ||
| <TreeItem id="budget" textValue="Budget.xlsx"> | ||
| <TreeItemContent> | ||
| Budget.xlsx | ||
| <PermissionPicker label="Budget.xlsx permission" /> | ||
| </TreeItemContent> | ||
| </TreeItem> | ||
| </TreeItem> | ||
| <TreeItem id="photos" title="Photos"> | ||
| <TreeItem id="sunset" textValue="Sunset.jpg"> | ||
| <TreeItemContent> | ||
| Sunset.jpg | ||
| <PermissionPicker label="Sunset.jpg permission" /> | ||
| </TreeItemContent> | ||
| </TreeItem> | ||
| </TreeItem> | ||
| </Tree> | ||
| ``` | ||
|
|
||
| ## Drag and drop | ||
|
|
||
| Tree supports drag and drop interactions when the `dragAndDropHooks` prop is provided using the <TypeLink links={docs.links} type={docs.exports.useDragAndDrop} /> hook. Users can drop data on the list as a whole, on individual items, insert new items between existing ones, or reorder items. React Aria supports drag and drop via mouse, touch, keyboard, and screen reader interactions. See the [drag and drop guide](dnd?component=Tree) to learn more. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps a little confusing because the starter example uses
keyboardNavigationBehavior="tab"by default already since it is a grid layout...Not sure how much we want to explain in the docs though.