diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index 81ce288d70..df8de60aa3 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix `transition` and `focus` prop combination for `PopoverPanel` component ([#3361](https://github.com/tailwindlabs/headlessui/pull/3361)) - Fix outside click in nested portalled `Popover` components ([#3362](https://github.com/tailwindlabs/headlessui/pull/3362)) - Fix restoring focus to correct element when closing `Dialog` component ([#3365](https://github.com/tailwindlabs/headlessui/pull/3365)) +- Fix `flushSync` warning for `Combobox` component with `immediate` prop enabled ([#3366](https://github.com/tailwindlabs/headlessui/pull/3366)) ## [2.1.1] - 2024-06-26 diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index f0e0c464a5..1fc681a9be 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -1321,12 +1321,37 @@ function InputFn< if (!data.immediate) return if (data.comboboxState === ComboboxState.Open) return - flushSync(() => actions.openCombobox()) - - // We need to make sure that tabbing through a form doesn't result in incorrectly setting the - // value of the combobox. We will set the activation trigger to `Focus`, and we will ignore - // selecting the active option when the user tabs away. - actions.setActivationTrigger(ActivationTrigger.Focus) + // In a scenario where you have this setup: + // + // ```ts + // {condition && ( + // + // + // + // )} + // ``` + // + // Then we will trigger the `openCombobox` in a `flushSync`, but we are + // already in the middle of rendering. This will result in the following + // warning: + // + // ``` + // Warning: flushSync was called from inside a lifecycle method. React + // cannot flush when React is already rendering. Consider moving this call + // to a scheduler task or micro task. + // ``` + // + // Which is why we wrap this in a `microTask` to make sure we are not in the + // middle of rendering. + d.microTask(() => { + flushSync(() => actions.openCombobox()) + + // We need to make sure that tabbing through a form doesn't result in + // incorrectly setting the value of the combobox. We will set the + // activation trigger to `Focus`, and we will ignore selecting the active + // option when the user tabs away. + actions.setActivationTrigger(ActivationTrigger.Focus) + }) }) let labelledBy = useLabelledBy()