Search code examples
javascripthtmlcssreactjstailwind-css

Checkboxes not working on click in Reactjs


So ,I am trying to make some checkboxes in a pop up filter menu on click of a button. Below here is the common code for the pop up menu

const MenuPop = ({onClose , visible, isLoading,item,values}) => {
  const handleClose = (e)=>{
    e.preventDefault()
    if(e.target.id==='parent'){
      onClose()
    }
  }
  if(!visible)
    return null;

    return (
    <div 
    id="parent" 
    className={`${values} fixed z-[100] inset-0 bg-[black] bg-opacity-50`}
    onClick={handleClose}
    >
      {item}

    </div>
  )
}

here are the different variables that I have used as props using a React hook

const useCommonItems = () => {
    const [visible, setvisible] = useState(false)
    const handleClose =()=>{
      setvisible(false)
    }
    return {
        visible,
        setvisible,
        handleClose
    }
}

here is my page where I have a button the opens the pop up menu on the click of a button

const App=()=>{
const {visible,setvisible,handleClose}=useCommonItems();//react hook to get commonly used variables
return (
<>
   <button onClick={e=>{
   e.preventDefault();
   //making the visible = true
   setvisible(true)
   }>Click Me </button>
   <MenuPop visible={visible} onClose={handleClose} values="flex justify-center items- 
    center" item={<Filter/>} />
<>
);}

here is the component that opens up as soon as the button "Click Me" above is click

const Filter = () => {
  const PriceArray = ["100", "300", "1000", "2000"];
  const [priceVariable, setPriceVariable] = useState(0);
  console.log(priceVariable)
  const headingClass = "text-[20px] text-blue-600 font-semibold";
  const inputClass =
    "mr-[15px] border-[2px] font-[300] w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 accent-blue-600 ";
  const parentCaseClass = "border-b-[2px] border-blue-600 mb-[20px] pb-[20px]";
  return (
    <div className="bg-[white] 450:w-[450px] w-[100%] p-[20px] rounded-[20px] grid grid-flow-row grid-cols-1 450:grid-cols-2">
      <div className={`Price ${parentCaseClass} `}>
        <p className={`${headingClass}`}>Price</p>
        {PriceArray.map((item, id) => (
          <div className="" key={id}>
            <input type="checkbox" value={item} id={name} name={item} className={inputClass} />
            <label htmlFor={item}>{item}</label>
          </div>
        ))}
      </div>  
    </div>
  );
};

So why are the checkboxes not working on clicking them?Can someone help?


Solution

  • A checkbox should have a checked attribute which holds a boolean value. More information here.

    What you can do is create a checkbox component like this:

    const Checkbox = ({ checked, onChange, id, className }) => {
      return (
        <input
          id={id}
          className={className}
          checked={checked}
          type="checkbox"
          onChange={onChange}
        />
     );
    };
    

    Use it like this:

    // import or create a constant called SOME_CHECKBOX_NAME_CONSTANT
    // that holds the label names
    
    const Component = () => {
      const [data, setData] = useState({
        isSomeUseCaseData: false,
      });
    
      const onChangeCheckbox = (event) => {
        setData({ isSomeUseCaseData: event.target.checked });
      };
    
      return (
        <div className="some-form-name">
          {Object.keys(data).map((item) => (
            <Checkbox
              key={item}
              id={`${item}-id`}
              checked={data[item]}
              onChange={onChangeCheckbox}
              className="some-class-name"
            >
             <span>{SOME_CHECKBOX_NAME_CONSTANT[item]}</span>
           </Checkbox>
          ))}
        </div>
      );
    };
    

    Now you have a controlled checkbox. Your Filter component might look like this:

    const Filter = () => {
      const PriceArray = ['100', '300', '1000', '2000'];
      const [priceVariable, setPriceVariable] = useState(0);
    
      const [data, setData] = useState({});
    
      const headingClass = 'text-[20px] text-blue-600 font-semibold';
      const inputClass = 'mr-[15px] border-[2px] font-[300] w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 accent-blue-600 ';
      const parentCaseClass = 'border-b-[2px] border-blue-600 mb-[20px] pb-[20px]';
    
      return (
        <div className="450:w-[450px] 450:grid-cols-2 grid w-[100%] grid-flow-row grid-cols-1 rounded-[20px] bg-[white] p-[20px]">
          <div className={`Price ${parentCaseClass} `}>
            <p className={`${headingClass}`}>Price</p>
              {PriceArray.map((item, id) => (
                <div
                  className=""
                  key={id}
                >
                 <Checkbox
                   value={item}
                   id={name}
                   name={name}
                   className={inputClass}
                   checked={data[item] || false}
                   onChange={(e) => {
                     setData(() => ({ ...data, [item]: e.target.checked }));
                   }}
                 />
                 <label htmlFor={item}>{item}</label>
               </div>
             ))}
           </div>
        </div>
      );
    };
    

    Audience please don't curse me in the comments, I did not have time to refactor @randeepsarma24's code.