-
Notifications
You must be signed in to change notification settings - Fork 42
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: Add support for onBlur
, and omit props that have no effect
#3125
Conversation
🦋 Changeset detectedLatest commit: 54693d7 The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
.changeset/silly-cycles-think.md
Outdated
@@ -0,0 +1,5 @@ | |||
--- | |||
"@navikt/ds-react": patch |
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.
Patch or minor? 🤔
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.
Leaning towards minor since lots of features are omitted from types (even if none of them worked before 😅 )
value={value} | ||
onBlur={() => virtualFocus.moveFocusToTop()} | ||
onBlur={composeEventHandlers(onBlur, virtualFocus.moveFocusToTop)} |
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.
I needed onBlur
for the example, so I only added composeEventHandlers
on that one for now. But should we add it to the other event handlers as well?
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.
Doesn't hurt to add it to all of them i guess, but not needed in this PR 🤷
Storybook demo89c9173b3 | 88 komponenter | 139 stories |
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.
Adding a button with type="submit"
under the combobox might make it easier to move focus and testing submit for the user 🚀
control, | ||
formState: { errors }, | ||
} = useForm<Inputs>({ | ||
reValidateMode: "onBlur", |
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.
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.
I'm not able to recreate this, when I've selected a value the error disappears for me (firefox).
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.
actually, i can get this state if i close the list options by navigating the mouse cursor up one from the first element. So nvm. I guess this would be a confusing state to end up in.
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.
Since combobox has a text input field, then the onChange for that should probably not cause rapid changes to the dom / form validation? (we can prevent validation on this onChange, but have it trigger on the selectedOptions onChange (to avoid the above situation).
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.
I get this state by only using keyboard or clicking "car" in dropdown then hitting "esc" to close menu. I guess most will click outside the menu to close it thus triggering onBlur, but would be best if it was experienced the same for both mouse and keyboard-users.
Hmm true about the onChange firing raid events, would not be optimal 🤔 Would it be possible to manually update validation-state within onToggleSelected
? Something like
onToggleSelected: (value, isSelected) => if isSelected -> updateValidation()
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.
Seems like i didn't properly understand how the Controller
function worked 🙈 Since we have full control over where field.onChange
is added, we avoid rapid events like you mentioned Julian 👍
I tested with this snippet and it seems to work like expected:
- Added
selectedOptions={field.value}
since we have to control the combobox - Changed to
reValidateMode: "onChange",
const Example = () => {
const {
handleSubmit,
control,
formState: { errors },
} = useForm<Inputs>({
reValidateMode: "onChange",
defaultValues: { transportmiddel: [] },
});
const onValidSubmit: SubmitHandler<Inputs> = (data) => {
alert(data);
};
return (
<form onSubmit={handleSubmit(onValidSubmit)}>
<Controller
control={control}
rules={{ required: "Du må velge minst ett transportmiddel." }}
name="transportmiddel"
render={({ field }) => (
<UNSAFE_Combobox
id="transportmiddel"
label="Hva er de kuleste transportmidlene?"
options={options}
isMultiSelect
error={errors.transportmiddel?.message}
ref={field.ref}
name={field.name}
selectedOptions={field.value}
onToggleSelected={(option, isSelected) => {
if (isSelected) {
field.onChange([...field.value, option]);
} else {
field.onChange(field.value.filter((v) => v !== option));
}
}}
/>
)}
/>
</form>
);
};
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.
I agree that we can validate on onChange
here. "onChange" in this case is actually onToggleSelected
. The reason for choosing onBlur
at first was to avoid too early validation if you need to select multiple items. But when thinking about it, that shouldn't be a problem as long as devs don't create too clever error messages.
Let's say you have selected 1 but need to select 3. Error message should be "you need to select at least 3 items". If you remove everyting, the error should be the same. If you add one, the error should still be the same. It would only be a problem if the error said like "select 2 MORE items", but I think that's an edge case. Even then, at least the error changes only when selecting, not on every keystroke 😅
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.
As far as I know, the teams I have had contact with about Combobox and react-hook-form use reValidateMode: "onChange"
.
aksel.nav.no/website/pages/eksempler/combobox/react-hook-form.tsx
Outdated
Show resolved
Hide resolved
aria-autocomplete={shouldAutocomplete ? "both" : "list"} | ||
aria-activedescendant={activeDecendantId} | ||
aria-describedby={ariaDescribedBy} | ||
aria-invalid={inputProps["aria-invalid"]} |
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.
I like grouping all the aria props near the bottom, could be a nice convention.
"size" | "onChange" | "value" | "defaultValue" | ||
| "size" | ||
| "onChange" | ||
| "value" | ||
| "defaultValue" | ||
| "onClick" | ||
| "onInput" | ||
| "type" | ||
| "role" | ||
| "onKeyUp" | ||
| "onKeyDown" | ||
| "autoComplete" |
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.
Is the reason for omitting these extra attributes simply that we use our own, internal ones?
Should we Pick<InputHTMLAttributes<HTMLInputElement>, "which" | "props" | "we" | "use">
instead?
I guess there are still a lot of attributes left that we don't actually use? 🤔
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.
The reason for omitting these (the ones I added) is because we override them, so they don't work anyways. So now you will get TS error if you try to use them, instead of just silently failing.
I'm not sure how strict we should be about which props to accept. One could argue that since the input is so specialized, we should use Pick
instead so that we know that we only offer props that works properly. This will avoid another "placeholder
incident" where we have to say that "yes, it's supported, but not really" 😅
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.
I'll change to Pick
in a new PR.
onBlur
, and omit props that have no effect
Also added example of usage with react-hook-form, which was the primary task originally 😅