Search code examples
javascripthtmlcssreactjsstyled-components

How to apply css type rules to Styled Components in React


Having the following html/css code that enables html elements to behave like a radio group:

.radios .radio{
    background-color:#c5e043;
    display:inline-block;
    width:20px;
    height:20px;
    cursor:pointer
}

.radios input[type=radio]{
    display:none
}

.radios input[type=radio]:checked + .radio{
    background-color:#241009
}
<div class="radios">
<div>
    <input type="radio" name="rGroup"  id="r1"  />
    <label class="radio" for="r1"></label>
    <input type="radio" name="rGroup"  id="r2" />
    <label class="radio" for="r2"></label>
    <input type="radio" name="rGroup"  id="r3" />
    <label class="radio" for="r3"></label></div>
</div>

I want to write in React some Styled components that behave in the same way but don't know how to write in styled components input[type=radio] and .radios input[type=radio]:checked + .radio.

Here is the code, a code sandbox here. It shows the elements but click isn't working, it doesn't change the selected element like in the above code.

What should be changed?

import React from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";

export const XSelectionBoxContainer = styled.div`
  background-color: #c5e043;
  display: inline-block;
  width: 20px;
  height: 20px;
  cursor: pointer;
`;

export const Xlabel = styled.label`
  background-color: #c5e043;
  display: inline-block;
  width: 20px;
  height: 20px;
  cursor: pointer;
`;

export const Xinput = styled.input`
  display: none;
  :checked {
    background-color: #241009;
  }
`;

function App() {
  const options = [
    {
      label: "first",
      value: "first",
      name: "radio-group"
    },
    {
      label: "second",
      value: "second",
      name: "radio-group"
    },
    {
      label: "third",
      value: "third",
      name: "radio-group"
    }
  ];
  return (
    <XSelectionBoxContainer>
      {options.map((option) => {
        return (
          <div key={option.label}>
            <Xlabel htmlFor={option.value}></Xlabel>
            <Xinput
              type="radio"
              name={option.value}
              value="1"
              id={option.value}
            />
          </div>
        );
      })}
    </XSelectionBoxContainer>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Solution

  • You need to place the label component below the input element so that you can use the + operator in css to style the label element if the input is :checked.

    Updated code below:

    import React from "react";
    import ReactDOM from "react-dom";
    import styled from "styled-components";
    
    export const XSelectionBoxContainer = styled.div`
      background-color: #c5e043;
      display: inline-block;
      width: 20px;
      height: 20px;
      cursor: pointer;
    `;
    
    export const Xlabel = styled.label`
      background-color: #c5e043;
      display: inline-block;
      width: 20px;
      height: 20px;
      cursor: pointer;
    `;
    
    export const Xinput = styled.input`
      display: none;
      &:checked { 
        & + label {
          background-color: #241009;
        }
      }
    `;
    
    function App() {
      const options = [
        {
          label: "first",
          value: "first",
          name: "radio-group"
        },
        {
          label: "second",
          value: "second",
          name: "radio-group"
        },
        {
          label: "third",
          value: "third",
          name: "radio-group"
        }
      ];
      return (
        <XSelectionBoxContainer>
          {options.map((option) => {
            return (
              <div key={option.label}>
                
                <Xinput
                  type="radio"
                  name={option.name}
                  value="1"
                  id={option.value}
                />
                <Xlabel htmlFor={option.value}></Xlabel>
              </div>
            );
          })}
        </XSelectionBoxContainer>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);