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

[v2] Attempt form submission when pressing Enter on Checkbox component #2962

Merged
merged 3 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/@headlessui-react/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Use `isFocused` instead of `isFocusVisible` for `Input` and `Textarea` components ([#2940](https://github.com/tailwindlabs/headlessui/pull/2940))
- Ensure `children` prop of `Field` component can be a render prop ([#2941](https://github.com/tailwindlabs/headlessui/pull/2941))
- Add `hidden` attribute to internal `<Hidden />` component when the `Features.Hidden` feature is used ([#2955](https://github.com/tailwindlabs/headlessui/pull/2955))
- Attempt form submission when pressing `Enter` on `Checkbox` component ([#2962](https://github.com/tailwindlabs/headlessui/pull/2962))

## [2.0.0-alpha.4] - 2024-01-03

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,47 @@ describe.each([
})
)
})

describe('Form submissions', () => {
it('should be possible to use in an uncontrolled way', async () => {
let handleSubmission = jest.fn()

render(
<form
onSubmit={(e) => {
e.preventDefault()
handleSubmission(Object.fromEntries(new FormData(e.target as HTMLFormElement)))
}}
>
<Checkbox name="notifications" />
</form>
)

// Focus the checkbox
await focus(getCheckbox())

// Submit
await press(Keys.Enter)

// No values
expect(handleSubmission).toHaveBeenLastCalledWith({})

// Toggle
await click(getCheckbox())

// Submit
await press(Keys.Enter)

// Notifications should be on
expect(handleSubmission).toHaveBeenLastCalledWith({ notifications: 'on' })

// Toggle
await click(getCheckbox())

// Submit
await press(Keys.Enter)

// Notifications should be off (or in this case, non-existant)
expect(handleSubmission).toHaveBeenLastCalledWith({})
})
})
22 changes: 13 additions & 9 deletions packages/@headlessui-react/src/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { FormFields } from '../../internal/form-fields'
import { useProvidedId } from '../../internal/id'
import type { Props } from '../../types'
import { isDisabledReactIssue7711 } from '../../utils/bugs'
import { attemptSubmit } from '../../utils/form'
import {
forwardRefWithAs,
mergeProps,
Expand Down Expand Up @@ -110,20 +111,22 @@ function CheckboxFn<TTag extends ElementType = typeof DEFAULT_CHECKBOX_TAG, TTyp

let handleClick = useEvent((event: ReactMouseEvent) => {
if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault()
event.preventDefault()
toggle()
})

let handleKeyDown = useEvent((event: ReactKeyboardEvent) => {
if (isDisabledReactIssue7711(event.currentTarget)) return event.preventDefault()

switch (event.key) {
case Keys.Space:
event.preventDefault()
toggle()
break
let handleKeyUp = useEvent((event: ReactKeyboardEvent<HTMLButtonElement>) => {
if (event.key === Keys.Space) {
event.preventDefault()
toggle()
} else if (event.key === Keys.Enter) {
attemptSubmit(event.currentTarget)
}
})

// This is needed so that we can "cancel" the click event when we use the `Enter` key on a button.
let handleKeyPress = useEvent((event: ReactKeyboardEvent<HTMLElement>) => event.preventDefault())

let { isFocusVisible: focus, focusProps } = useFocusRing({ autoFocus: props.autoFocus ?? false })
let { isHovered: hover, hoverProps } = useHover({ isDisabled: disabled ?? false })
let { pressed: active, pressProps } = useActivePress({ disabled: disabled ?? false })
Expand All @@ -139,7 +142,8 @@ function CheckboxFn<TTag extends ElementType = typeof DEFAULT_CHECKBOX_TAG, TTyp
'aria-disabled': disabled ? true : undefined,
indeterminate: indeterminate ? 'true' : undefined,
tabIndex: 0,
onKeyDown: disabled ? undefined : handleKeyDown,
onKeyUp: disabled ? undefined : handleKeyUp,
onKeyPress: disabled ? undefined : handleKeyPress,
onClick: disabled ? undefined : handleClick,
},
focusProps,
Expand Down
Loading