Search code examples
css-selectorsradio-buttonradio-grouppseudo-classchecked

Within a radio-group how does one target via (a) css-selector(s) unchecked controls while there is also a checked/focused control amongst the group?


Is it possible within a radio-group to change the style of a radio button that has not been checked after the other button has been checked?

I have 5 radio boxes. I gave a custom style to the checked ones with the :checked pseudo class. But when a control is checked I want the others to be less visible. I used the negation :not(:checked), but in case none of the controls is checked, all of them are less visible. I just want the unchecked controls of a radio-group to be less visible after another control of this group has been checked.

How can I do this with javascript or css?


Solution

  • The OP might make use of the :focus-within css pseudo class like demonstrated with the below provided example.

    /*
    fieldset:focus-within span {
      opacity: .3;
    }
    fieldset:focus-within [type="radio"]:focus + span {
      opacity: 1;
    }
    */
    fieldset:focus-within [type="radio"]:not(:checked) + span {
      opacity: .3;
    }
    <form>
      <fieldset>
        <legend>1st radio group</legend>
    
        <label>
          <input type="radio" name="foo-bar"/>
          <span>Foo</span>
        </label>
        <label>
          <input type="radio" name="foo-bar" checked/>
          <span>Bar</span>
        </label>
        <label>
          <input type="radio" name="foo-bar"/>
          <span>Baz</span>
        </label>
      </fieldset>
    
      <fieldset>
        <legend>2nd radio group</legend>
    
        <label>
          <input type="radio" name="bizz-buzz"/>
          <span>Bizz</span>
        </label>
        <label>
          <input type="radio" name="bizz-buzz"/>
          <span>Booz</span>
        </label>
        <label>
          <input type="radio" name="bizz-buzz"  checked/>
          <span>Buzz</span>
        </label>
      </fieldset>
    </form>

    The next provided example applies fixes and improvements (e.g. tab navigable, valid markup, no empty / or unnecessary decorating span elements) to the OP's codepen code.

    body { zoom: .9; }
    fieldset { margin: 0 0 5px 0; padding: 0; border: none; }
    
    .insurance-container [type="radio"] {
      /*
        do not apply ... display: none; ...
        for it will prevent tab navigation.
      */
      position: absolute;
      left: -40px;
    }
    .insurance-container label {
      position: relative;
    }
    .insurance-container .insurance-item {
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 4px;
      border: 1px solid #e9e9e9;
      padding: 6px;
    }
    .insurance-container .insurance-item::after {
      /*
        - do not rely on empty elements for visually
          drawing a replacement of a form-control.
        - use one of the pseudo elements like `::after`
          or `::before` for such purpose.    
      */
      content: "";
      height: 16px;
      width: 16px;
      background-color: #dddddd;
      border: 1px solid #dddddd;
      border-radius: 50%;
      transition: 500ms all;
      -webkit-transition: 500ms all;
      -moz-transition: 500ms all;
      -ms-transition: 500ms all;
      -o-transition: 500ms all;
    }
    .insurance-container [type="radio"]:checked + .insurance-item::after {
      border-color: #0078d6;
      border-width: 8px;
    }
    
    .insurance-container [type="radio"]:checked + .insurance-item {
      border: 1px solid #0078d6;
      background-color: #f8f8f8;
    }
    .insurance-container:focus-within [type="radio"]:not(:checked) + .insurance-item {
      /* make use of the `:focus-within` pseudo class */
      opacity: 0.5;
    }
    <fieldset class="insurance-container">
      <legend>first radio group</legend>
    
      <label>
        <input type="radio" value="insurance-1" name="first-group"/>
    
        <span class="insurance-item">
          <span class="wb-type-heading-xs">Input Title</span>
          <span class="wb-type-price">Number Value</span>
          <span class="wb-type-price">Custom Text</span>
        </span>
      </label>
      <label>
        <input type="radio" value="insurance-1" name="first-group"/>
        <span class="insurance-item">
          <span class="wb-type-heading-xs">Input Title</span>
          <span class="wb-type-price">Number Value</span>
          <span class="wb-type-price">Custom Text</span>
        </span>
      </label>
      <label>
        <input type="radio" value="insurance-1" name="first-group"/>
        <span class="insurance-item">
          <span class="wb-type-heading-xs">Input Title</span>
          <span class="wb-type-price">Number Value</span>
          <span class="wb-type-price">Custom Text</span>
        </span>
      </label>
    </fieldset>
    
    <fieldset class="insurance-container">
      <legend>second radio group</legend>
    
      <label>
        <input type="radio" value="insurance-2" name="second-group"/>
    
        <span class="insurance-item">
          <span class="wb-type-heading-xs">Input Title</span>
          <span class="wb-type-price">Number Value</span>
          <span class="wb-type-price">Custom Text</span>
        </span>
      </label>
      <label>
        <input type="radio" value="insurance-2" name="second-group"/>
        <span class="insurance-item">
          <span class="wb-type-heading-xs">Input Title</span>
          <span class="wb-type-price">Number Value</span>
          <span class="wb-type-price">Custom Text</span>
        </span>
      </label>
      <label>
        <input type="radio" value="insurance-2" name="second-group"/>
        <span class="insurance-item">
          <span class="wb-type-heading-xs">Input Title</span>
          <span class="wb-type-price">Number Value</span>
          <span class="wb-type-price">Custom Text</span>
        </span>
      </label>
    </fieldset>