Skip to content

Disabling TableView/ListView keyboard navigation and press interactions if collection is empty#3422

Merged
devongovett merged 16 commits into
mainfrom
tab_into_table_empty
Sep 8, 2022
Merged

Disabling TableView/ListView keyboard navigation and press interactions if collection is empty#3422
devongovett merged 16 commits into
mainfrom
tab_into_table_empty

Conversation

@LFDanLu
Copy link
Copy Markdown
Member

@LFDanLu LFDanLu commented Aug 19, 2022

Closes #3399

Known issues:

  • clicking on a resizable column header, closing the menu, and hitting ArrowLeft will move focus onto the adjacent resizer instead of onto the adjacent column header
  • hitting Enter/Space while focused on the TableView's select all checkbox doesn't do anything

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Test the "renderEmptyState" TableView story and the "empty" ListView stories. You should be able to tab to the link in the illustrated message and the select all checkbox should be disabled for the TableView. Empty CardViews shouldn't work at the moment

🧢 Your Project:

RSP

'aria-multiselectable': state.selectionManager.selectionMode === 'multiple' ? 'true' : undefined
},
state.isKeyboardNavigationDisabled ? {} : collectionProps,
state.collection.size === 0 || state.isKeyboardNavigationDisabled ? {} : collectionProps,
Copy link
Copy Markdown
Member Author

@LFDanLu LFDanLu Aug 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opted for putting this logic here so this behavior would apply to all grid components, not just TableView.

Note that this would prevent the user from tabbing to the column headers to resize them if the TableView is empty, but I figured this was a non issue since the Table doesn't have row data to display. Perhaps we should remove the resize menu entirely for this case?

EDIT: the above isn't 100% true (the column resize buttons still have tabindex = 0) but it would be a simple enough task to hide that as well

this makes resizing, clicking on column header and other interactions all inert if the table is empty. Partially makes these changes TableView specific instead of grid wide, to confirm with team.
also fixes some small things the tests revealed like how the hidden inputs in the resizer werent disabled
@LFDanLu LFDanLu changed the title (WIP) Disabling grid keyboard navigation if collection is empty (WIP) Disabling TableView/ListView keyboard navigation and press interactions if collection is empty Aug 23, 2022
@adobe-bot
Copy link
Copy Markdown

test is skipped for now due to outstanding bug that is fixed in separate PR
@LFDanLu
Copy link
Copy Markdown
Member Author

LFDanLu commented Aug 23, 2022

Known issues:

  • clicking on a resizable column header, closing the menu, and hitting ArrowLeft will move focus onto the adjacent resizer instead of onto the adjacent column header
  • hitting Enter/Space while focused on the TableView's select all checkbox doesn't do anything
    • pre-existing, will investigate and fix in separate PR

@adobe-bot
Copy link
Copy Markdown

Comment on lines +97 to +99
// TODO: this will affect all grids, maybe make it specific to Table via useTableState?
// something like isInteractionDisabled: state.collection.size === 0
isDisabled: state.collection.size === 0
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to opinions here. I could make the changes in this PR to be grid wide instead of only for TableView which would make the above change valid. If we wanna only affect TableView, I can add something specific to the table state instead OR add isDisabled to useGridCell/useGridRow's props (feels iffy). A third option is that we are ok with the above change even though we are scoping this behavior to TableView, especially since TableView is the only grid that has grid cells and rows when the collection is empty

expect(tree.queryByRole('slider')).toBeFalsy();
});

it.skip('should re-enable functionality when the table recieves items', function () {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned, skipped for now until #3414 goes in

@LFDanLu LFDanLu changed the title (WIP) Disabling TableView/ListView keyboard navigation and press interactions if collection is empty Disabling TableView/ListView keyboard navigation and press interactions if collection is empty Aug 23, 2022
@adobe-bot
Copy link
Copy Markdown

@adobe-bot
Copy link
Copy Markdown

Copy link
Copy Markdown
Member

@reidbarber reidbarber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one comment, everything else looks good


return (
<Flex direction="column">
<ActionButton width="100px" onPress={() => setShow(show => !show)}>Toggle items</ActionButton>
Copy link
Copy Markdown
Member

@reidbarber reidbarber Aug 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you toggle items in, select all, then toggle items out, the select all checkbox is shown as checked and is keyboard navigable even though it is disabled. Not sure if this is just how the story is written and a non-issue, or a separate issue.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It remains keyboard navigable even if you undo the select all again. As soon as it has gotten focus, that's what TableView will send focus to. This happens with the Column headers as well. Toggle the items, navigate to col 3, then toggle the items off. Tab will continue to send you to Column Header 3

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this, I'll probably go the route of clearing the tab index if the grid is empty. One possible issue may be if the collection doesn't properly get an updated tab index but I imagine I could override that as well if need be

@adobe-bot
Copy link
Copy Markdown

Comment thread packages/@adobe/spectrum-css-temp/components/table/skin.css
onAction: onCellAction ? () => onCellAction(node.key) : onAction,
// TODO: this will affect all grids, maybe make it specific to Table via useTableState?
// something like isInteractionDisabled: state.collection.size === 0
isDisabled: state.collection.size === 0
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it both non-interactive and non-navigable? or should we name the prop something else? or is that what you're suggesting in the comment?
Lets only do this for Table for now? I assume we'll be asked to do this for ListView eventually, but sounds like not yet?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR also covers ListView.

Also, if the collection is empty, wouldn't there be no grid cells? I guess only in the case of tableview because of the headers?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, only TableView has grid cells when the collection is empty, CardView and TagGroup don't. Was just a bit worried that there might people using these grid hooks directly to build a table (or some other grid pattern) that wouldn't want to disable interactions when their table is empty

},
onChange
onChange,
disabled: isDisabled
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rather than disabling this, shouldn't we just not render the menu button and not display the resizer on hover?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should work, I just felt like it would be appropriate to give the user the ability to disable a column resizer but we can add that when a use case arises.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, since I ran into issues here I'm going to go back to the isDisabled approach

}

let _TableColumnHeaderButton = (props, ref: FocusableRef<HTMLDivElement>) => {
let {isEmpty} = useTableContext();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the table is empty, maybe we just render a TableColumnHeader instead of one with a menu?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we need to render the TableResizeColumnHeader if it is resizable, otherwise flipping from empty to non-empty doesn't replace the in view columns with resizable columns (caching probably?)

@devongovett
Copy link
Copy Markdown
Member

One small issue I noticed: the column header cells still have tabindex="-1" set. Seems like you can't tab directly to them, but if you right click on them they become tabindex="0", and then you can tab to them. We might want to remove the tab index completely when disabled?

@LFDanLu
Copy link
Copy Markdown
Member Author

LFDanLu commented Sep 7, 2022

@devongovett Hm, I'm not seeing that right click behavior actually. I'll still go ahead and remove the tab index when the table column headers so the previously focused key doesn't interfere with the empty TableView behavior but just wanna double check: what story/browser combo were your using?

@devongovett
Copy link
Copy Markdown
Member

renderEmptyState in Safari.

@LFDanLu LFDanLu changed the title Disabling TableView/ListView keyboard navigation and press interactions if collection is empty (WIP) Disabling TableView/ListView keyboard navigation and press interactions if collection is empty Sep 7, 2022
@LFDanLu
Copy link
Copy Markdown
Member Author

LFDanLu commented Sep 7, 2022

@devongovett kk good to know, maybe a old Safari bug, not seeing that on my end with the old storybook.

TODO: seeing some weirdness when toggling items back and forth, resizers appear for some columns and not for others, need to investigate further. The spacing between the checkbox and the column header is too close locally too

the columns in view arent updated from TableColumnHeaders to ResizableTableColumnHeader when going from no items to items in the empty TableView story, so I went back to disabling the resize column button instead
@LFDanLu
Copy link
Copy Markdown
Member Author

LFDanLu commented Sep 7, 2022

One last issue I'm digging into: useVirtualizer overrides the provided grid tabindex, means that the table itself isn't tabbable if the user had focused any of the column headers before the table became empty

@adobe-bot
Copy link
Copy Markdown

virtualizer will provide tabindex=-1 if the focused item is still in view which means a empty table will have tabindex -1 if the column header was focused last. We want the table to be tabbable when empty so we override this
@LFDanLu LFDanLu changed the title (WIP) Disabling TableView/ListView keyboard navigation and press interactions if collection is empty Disabling TableView/ListView keyboard navigation and press interactions if collection is empty Sep 7, 2022
Comment on lines +423 to +424
// Override virtualizer provided tabindex if TableView is empty so it is tabbable.
{...mergeProps(otherProps, virtualizerProps, collection.size === 0 && {tabIndex: 0})}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useVirtualizer will return tabindex=-1 if the focused view is still in the TableView, which is problematic for the empty case because the last focused view could be a column header prior to the TableView becoming empty and thus would still be in view. Debated putting this logic into useVirtualizer but I figured that would be too wide of a change. Specifically, in case someone was using Virtualizer to create a component that would keep some focusable views even when the collection was empty but they wanted those view to still be tabbable/didn't want the virtualizer to be tabbable

@adobe-bot
Copy link
Copy Markdown

devongovett
devongovett previously approved these changes Sep 7, 2022
Copy link
Copy Markdown
Member

@devongovett devongovett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

One question: is there any value to focusing the collection itself when it is empty and contains a focusable element? Seems like it's kind of an extra tab stop in that case. Maybe we should do something like we do with tabs where if there are no focusable children, then the collection is focusable, otherwise not? Maybe a future improvement.

@LFDanLu
Copy link
Copy Markdown
Member Author

LFDanLu commented Sep 7, 2022

I mainly did it for consistency with ListView's existing behavior (aka how focus moves to the ListView itself when the collection becomes temporarily empty) and to have the announcement of the link happen separately from entering the tableview. Neither of the two are very strong reasons, and making it behave like tabs sounds like a good idea for consistency. Happy to handle that in a follow up

@adobe-bot
Copy link
Copy Markdown

@adobe-bot
Copy link
Copy Markdown

@adobe-bot
Copy link
Copy Markdown

@devongovett devongovett merged commit 09a0489 into main Sep 8, 2022
@devongovett devongovett deleted the tab_into_table_empty branch September 8, 2022 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[TableView] Interactive empty state support

5 participants