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

textfield with popover + listbox captured enter key press incorrectly #13092

Open
shopifybradleystaples opened this issue Jan 21, 2025 · 0 comments

Comments

@shopifybradleystaples
Copy link

If you have a TextField with clearButton as an activator for a popover with a listbox, once you have a value selected in the listbox trying to use the enter key on the clearButton fails, as the listbox code handles the enter keypress and prevents it from propagating upwards through the dom, so that the TextField's onClearButtonClick never fires.

The playground code has console.logs + text decriptions to call it out.

playground link:

playground code if link doesn't work
const [selectedOption, setSelectedOption] = useState(undefined);
const [searchValue, setSearchValue] = useState('');
const [popoverOpen, setPopoverOpen] = useState(false);

const togglePopoverOpen = () => {setPopoverOpen((popoverOpen) => !popoverOpen)};

const options = [
  {value: '1', label: 'value one'},
  {value: '2', label: 'value two'},
  {value: '3', label: 'value three'},
  {value: '4', label: 'value four'},
  {value: '5', label: 'value five'},
  {value: '6', label: 'value six'},
  {value: '7', label: 'value seven'},
  {value: '8', label: 'value eight'},
  {value: '9', label: 'value nine'},
];

const filteredOptions = useMemo(() => {
  if (!searchValue) return options;
  return options.filter((option) => option.label.includes(searchValue));
}, [searchValue]);

const activator = (
  <TextField
    clearButton
    labelHidden
    autoComplete="off"
    value={searchValue}
    onChange={(newValue) => {
      console.log('TextField.onChange', {newValue});
      setSearchValue(newValue);
      setPopoverOpen(true);
    }}
    onClearButtonClick={() => {
      console.log('TextField.onClearButtonClick');
      setSelectedOption(undefined);
      setSearchValue('');
    }}
    onBlur={() => {
      console.log('TextField.onBlur');
      setPopoverOpen(false);
    }}
    onFocus={() => setPopoverOpen(true)}
   />
);

return (
  <div style={{padding: '20px', width: '200px'}}>
    <Text as="p"><pre>
      searchValue: {searchValue}<br />
      selectedOption.value: {selectedOption?.value}<br />
      selectedOption.label: {selectedOption?.label}<br />
      <br />
    </pre></Text>
    <Button type="button">tab placeholder 1</Button>
    <br />
    <br />
    <Popover
      active={popoverOpen}
      activator={activator}
      onClose={() => {}}
      preferInputActivator={false}
      autofocusTarget="none"
      ariaHaspopup="listbox"
      preferredAlignment="left"
      preferredPosition="mostSpace"
      fullWidth
      fluidContent={false}
      hideOnPrint
    >
      <Popover.Pane>
        <Listbox
          onSelect={(newValue) => {
            const matchingOption = options.find((opt) => opt.value === newValue);
            console.log('Listbox.onSelect', {newValue, matchingOption});
            setSelectedOption(matchingOption || undefined);
            setSearchValue(matchingOption?.label || '');
          }}
          enableKeyboardControl
          autoSelection={AutoSelection.First}
         >
          {filteredOptions.map((opt) => {
            const isSelected = selectedOption === opt.value;
            return (
              <Listbox.Option value={opt.value} selected={isSelected}>
                <Listbox.TextOption value={opt.value} selected={isSelected}>
                  <Box minWidth="100px" padding="100">
                    <Text fontWeight="bold" as="span" alignment="center">{opt.label}</Text>
                  </Box>
                </Listbox.TextOption>
              </Listbox.Option>
            );
          })}
        </Listbox>
      </Popover.Pane>
    </Popover>
    <br />
    <Button type="button">tab placeholder 1</Button>
    <br /><br /><hr /><br />
    <Box width="500px">
      <Text as="p">There are two problems that occur here:</Text><br />
      <Text as="p" fontWeight="bold">Keyboard Controls - Enter Key</Text>
      <Box inlinePadding="400">
        <ul>
          <li>
            Working as expected
            <ol>
              <li>When a value is selected from the popover with the keyboard (closing the popover)</li>
              <li>The user tabs to the clear button</li>
              <li>Presses enter</li>
              <li>The field clears as expected</li>
            </ol>
          </li>
          <li>
            Not working as expected
            <ol>
              <li>When a value is selected with the keyboard</li>
              <li>The user clicks outside the form (to blur the input)</li>
              <li>Refocuses the input (with either keyboard or mouse)</li>
              <li>Tabs to the clear button</li>
              <li>Pressing enter does nothing</li>
              <li>Probably related to this code? <a href="https://github.com/Shopify/polaris-internal/blob/main/polaris-internal/src/components/Listbox/Listbox.tsx#L486-L490">lines 486-490</a> and also 431-440</li>
            </ol>
          </li>
        </ul>
      </Box>
      
      <Text as="p" fontWeight="bold">TextField onBlur w/ clearButton</Text>
      <Box inlinePadding="400">
        <ul>
          <li>enter a value in text field</li>
          <li>use tab key to focus clear button</li>
          <li>use tab key to blur off of clear button</li>
          <li>textfield's onBlur never fires, popover stays open</li>
          <li><a href="https://github.com/Shopify/polaris/issues/12964">filed issue</a></li>
        </ul>
      </Box>
    </Box>
  </div>
);
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

No branches or pull requests

1 participant