Set checkbox checked state of checkbox group programmatically in Formik

Viewed 555

I have a checkbox group (checkboxes with the same name), that I'd like to toggle them through an external button. The parent component will map over the data and create multiple checkboxes given the data, like so:

(options.map(
    option => (
        <Field
            name={field.name}
            value={option.value}
            component={CheckBoxButton}
        />
    )
)}

And the CheckBoxButton is

const CheckBoxButton = ({
    value,
    field,
    ...props
}) => {
    const [activeState, setActiveState] = useState(false)

    return (
        <div>
            <Field
                type="checkbox"
                {...field}
                {...props}
                value={value}
                checked={activeState}
            />

            <Button
                active={activeState}
                onClick={() => {
                    setActiveState(!activeState)
                }}
            >
                Toggle Checkbox
            </Button>
        </div>
    )
}

Now on submission, it seems the checked={activeState} value passed to the field seemed to be ignored, nor that it triggers onChange when changed. I have tried to use setFieldValue() but since we have multiple checkboxes with the same name, it only captures the last value. To use it means I'd have to manually structure the value array and pop/add values, which seems like an overkill.

I also tried using useRef and setting ref.current.checked manually, but at no use.

Any insights on what I might be doing wrong, or how to properly set the value programmatically?

1 Answers

So, I managed to get a workaround that solves the problem by wrapping the button (now a div) and checkbox within the same Label, and overriding the state within the onChange event of the field. Each field would have a unique identifier id which the label binds to using htmlFor. While a valid workaround, it would still be nice to have a programmatic way to do so.

const CheckBoxButton = ({value,field,...props}) => {
    const [activeState, setActiveState] = useState(active)
    const { handleChange } = useFormikContext()

    const fieldId = `${field.name}-${value}`

    return (
        <label htmlFor={fieldId}>
            <Field
                id={fieldId}
                type="checkbox"
                {...field}
                {...props}
                value={value}
                onChange={(event) => {
                    setActiveState(!activeState)
                    handleChange(event)
                }}
                className={style.checkbox}
            />
            <span active={activeState} >
                Toggle Checkbox
            </span>
        </label>
    )
}
Related