Reputation: 95
I want to make very flexible checkbox, that works this way
https://css-tricks.com/indeterminate-checkboxes/
:
I want to my checkbox have three options: unchecked, checked and indeterminate. Indeterminate: if all checkboxes connected with this indeterminate checkbox are checked , this indeterminate checkbox gets checked. My checkbox looks so:
import classNames from 'classnames';
import React from 'react';
interface IProps {
name?: string;
className?: string;
style?: React.CSSProperties;
label?: string;
color?: 'primary' | 'success' | 'secondary' | 'danger' | 'warning' | 'info' | 'light' | 'dark';
value?: string;
disabled?: boolean;
checked?: boolean;
onChange?: () => void;
indeterminate?: boolean;
}
type DefaultProps = Partial<IProps>;
const defaultProps: DefaultProps = {
color: 'primary',
disabled: false,
};
const Checkbox: React.FC<IProps> = (props) => {
const {label, color, disabled, name, value, indeterminate, onChange, checked, ...nextProps} = props;
return (
<div className="checkbox-content">
<label className={classNames(
{...nextProps},
'checkbox',
`checkbox-${color}`,
disabled && 'checkbox-disabled',
indeterminate && `checkbox-${color}-indeterminate`
)}
>
<input
type="checkbox"
name={name && name}
value={value && value}
checked={checked}
onChange={onChange}
/>
<span>{label}</span>
</label>
</div>
);
};
Checkbox.defaultProps = defaultProps;
Checkbox.displayName = 'CheckBox';
export default Checkbox;
function Application () {
const [isChecked, setChecked] = React.useState(false);
const handleChange = () => {
setChecked(!isChecked);
};
return (
<div>
<Checkbox label="initial" onChange={handleChange} checked={isChecked} />
</div>
);
}
I dont have any idea, how to do it properly because I want to my component be fully reusable.
Upvotes: 8
Views: 10173
Reputation: 2691
As your referenced article states, you need to set indeterminate
through Javascript. Therefore it's required to create a useEffect
handler that is responsible for doing this.
// snippet
const {indeterminate} = props;
const cRef = useRef();
useEffect(() => {
cRef.current.indeterminate = indeterminate;
}, [cRef, indeterminate]);
cRef
gives us a reference to the input
element so we can set the required attribute. The useEffect
therefore requires two dependencies: cref
for the element and indeterminate
as the props that it get's from its parent.
Full working code might look like this.
import { useEffect, useRef, useState } from "react";
import "./styles.css";
import classNames from "classnames";
const Checkbox = ({
indeterminate = false,
label,
color,
disabled,
name,
value,
onChange,
checked,
...props
}) => {
const cRef = useRef();
useEffect(() => {
cRef.current.indeterminate = indeterminate;
}, [cRef, indeterminate]);
return (
<div className="checkbox-content">
<label
className={classNames(
{ ...props },
"checkbox",
`checkbox-${color}`,
disabled && "checkbox-disabled",
indeterminate && `checkbox-${color}-indeterminate`
)}
>
<input
type="checkbox"
name={name}
value={value}
checked={checked}
onChange={onChange}
ref={cRef}
/>
<span>{label}</span>
</label>
</div>
);
};
export default function App() {
const [isChecked, setChecked] = useState(false);
const handleChange = () => {
setChecked(!isChecked);
};
return (
<div>
<Checkbox
label="initial"
onChange={handleChange}
checked={isChecked}
indeterminate
/>
</div>
);
}
Upvotes: 9