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

ComboBox.Input add additional API props #1256

Closed
saulflores95 opened this issue Mar 18, 2022 Discussed in #1255 · 3 comments · Fixed by #1265
Closed

ComboBox.Input add additional API props #1256

saulflores95 opened this issue Mar 18, 2022 Discussed in #1255 · 3 comments · Fixed by #1265

Comments

@saulflores95
Copy link

Discussed in #1255

Originally posted by saulflores95 March 18, 2022

What package within Headless UI are you using?

@headlessui/react

What version of that package are you using?

v1.5.0

What browser are you using?

Chrome

Currently using headless UI Combo Box we are using it to be able to select existing 'tags' and if a tag does not exist we create it by clicking on an icon that was added. This onClick event triggers a method called addOnClick.

The functionality we want is to detect when the 'Enter is pressed I want to trigger the same addOnClick Method.

The component looks as such.

const SelectInputWithSearch: FC<SelectInputWithSearchProps> = ({
  data,
  label,
  handleInputChange,
  handleSelect,
  addOnClick,
  ...inputProps
}) => {
  const [selectedData, setSelectedData] = useState("");

  const handleSelection = (selected: string) => {
    setSelectedData(selected);
    handleSelect(selected);
  };

  return (
    <Combobox as="div" value={selectedData} onChange={handleSelection}>
      <Combobox.Label className="block text-sm font-medium text-gray-700 ">
        {label}
      </Combobox.Label>
      <div className="relative mt-1 w-full">
        <Combobox.Button className="absolute inset-y-0 left-0 flex items-center rounded-r-md px-2 focus:outline-none">
          <SearchIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
        </Combobox.Button>

        <Combobox.Input
          className="w-full text-black rounded-md border border-gray-300 bg-white py-2 pl-8 pr-10 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm"
          onChange={handleInputChange}
          displayValue={(tag: string) => tag}
        />

        <Combobox.Button className="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
          {data.length > 0 ? (
            <SelectorIcon
              className="h-5 w-5 text-gray-400"
              aria-hidden="true"
            />
          ) : (
            <PlusIcon
              className="h-5 w-5 text-gray-400"
              aria-hidden="true"
              onClick={(e) => {
                e.preventDefault();
                addOnClick();
                setSelectedData("");
              }}
            />
          )}
        </Combobox.Button>

        {data.length > 0 && (
          <Combobox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
            {data.map((tag) => (
              <Combobox.Option
                key={tag}
                value={tag}
                className={({ active }) =>
                  classNames(
                    "relative cursor-default select-none py-2 pl-3 pr-9",
                    active ? "bg-indigo-600 text-white" : "text-gray-900",
                  )
                }
              >
                {({ active, selected }) => (
                  <>
                    <span
                      className={classNames(
                        "block truncate",
                        `${selected && "font-semibold"}`,
                      )}
                    >
                      {tag}
                    </span>
                  </>
                )}
              </Combobox.Option>
            ))}
          </Combobox.Options>
        )}
      </div>
    </Combobox>
  );
};
export default SelectInputWithSearch;

Currently, it is not shown in the docs if it's possible to expand the current onKeyDown functionality that headless UI already provides.

By taking a look at headless UI we can see there is an interface that defines the two possible props to pass down

interface InputRenderPropArg {
    open: boolean;
    disabled: boolean;
}

and a type where we can see the onKeyDown event being an option.

declare type InputPropsWeControl = 'id' | 'role' | 'type' | 'aria-labelledby' | 'aria-expanded' | 'aria-activedescendant' | 'onKeyDown' | 'onChange' | 'displayValue';

Is there any possible way of augmenting/expanding the keyDown prop? For example, just wanting to trigger the addOnClick method when a key down event is detected an enter key being pressed?

For example

        <Combobox.Input
          className="w-full text-black rounded-md border border-gray-300 bg-white py-2 pl-8 pr-10 shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 sm:text-sm"
          onChange={handleInputChange}
          displayValue={(tag: string) => tag}
          onKeyDown={() => {console.log('Extra things happening on keydown}}
        />
@RobinMalfait
Copy link
Member

Hey! Thank you for your bug report!
Much appreciated! 🙏

This should be fixed by #1265, and will be available in the next release. The PR allows you to write your own event handlers like onClick, onKeyDown, ... even if we also provide those. Your handlers will be executed before ours which gives you an opportunity to do anything to the event (even event.preventDefault()) if you would like to for whatever reason.

You can already try it using npm install @headlessui/react@insiders or yarn add @headlessui/react@insiders.

@saulflores95
Copy link
Author

That is awesome @RobinMalfait thank you for the speedy response! Going to try it out.

@akhiln28
Copy link

@saulflores95 Are you able to customise the onClick to trigger addOnClick when you press enter for a combobox option with the tag doesn't exist?
I am trying to do the same with with @headlessui/react@insiders with no luck.

My code looks something like this

<Combobox.Options className={'absolute top-10 bg-white rounded-md overflow-y-auto'}>
    {filteredOptions.map(option => (
        <Combobox.Option key={option} value={option}>
            {({ active, selected }) => (
                <div className={`${active ? 'bg-slate-300 p-2' : ''} p-2`}>
                    {option}
                </div>
            )}
        </Combobox.Option>
    ))}
    {filteredOptions.length === 0 &&
        <Combobox.Option as="button" key={query} value={query} className={'text-gray-800 p-2'} onClick={() => {
            options.push(query)
            console.log("create onclick: ", query)
            setSelected(query)
        }}
        >
            {({ active, selected }) => (
                <div className={`${active ? 'bg-slate-300 p-2 rounded-md' : ''} p-2`}>
                    Create <span className="font-bold">{query}</span>
                </div>
            )}
        </Combobox.Option>
    } 
</Combobox.Options>

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 a pull request may close this issue.

3 participants