skip to Main Content

I’m trying to show/hide some content just using CSS and radio buttons. I found something on Stack Overflow that does the trick
https://jsfiddle.net/LLornfn8/

However, I need to wrap my radios in some divs to handle some general styling which means the original JSFiddle code breaks, for example:

#input_description:checked ~ #contentDescription, #input_shipping:checked ~ #contentShipping  {
    display: block;
}

#contentDescription, #contentShipping{
  display: none;
}

.radio_item_menu:checked + .label_item_menu {
  font-weight: bold;
}
<div id="radioGroup">
 <div class="myRadioStyle">
  <input type="radio" name="navbar_menu_store" id="input_description" class="radio_item_menu">
  <label for="input_description" class="label_item_menu">Description</label>
 </div>
 <div class="myRadioStyle">
  <input type="radio" name="navbar_menu_store" id="input_shipping" class="radio_item_menu">
  <label for="input_shipping" class="label_item_menu">Shipping</label>
 </div>
</div>

<div id="contentDescription"><p class="testo_scheda">
This is some text</p>
</div>

<div id="contentShipping"><p class="testo_scheda">
This is some other text</p>
</div>

I’m not that familiar with selectors like ~. I am wondering if there is still a way to make this work?

I’ve looked around on Stack Overflow and found a few similar things but they all seem to handle it much like the original example rather than if objects are nested differently. I’ve tried playing around with different selectors to try to target the hidden divs but I still can’t get it to work. Nothing ever shows when you make the selections.

2

Answers


  1. With your actual HTML structure, the pseudo class :has() would be helpfull, unfortunately it is not yet well implemented. Firefox fails at this time. https://developer.mozilla.org/en-US/docs/Web/CSS/:has

    Here is the theorize example to test elsewhere than in Firefox
    (below this snippet, two other snippet working everywhere requiring to modify HTML – last snippet should be what you look for)

    #radioGroup:has(#input_description:checked ) ~ #contentDescription, #radioGroup:has(#input_shipping:checked )~ #contentShipping  {
        display: block;
    }
    
    #contentDescription, #contentShipping{
      display: none;
    }
    
    .radio_item_menu:checked + .label_item_menu {
      font-weight: bold;
    }
    <div id="radioGroup">
     <div class="myRadioStyle">
      <input type="radio" name="navbar_menu_store" id="input_description" class="radio_item_menu">
      <label for="input_description" class="label_item_menu">Description</label>
     </div>
     <div class="myRadioStyle">
      <input type="radio" name="navbar_menu_store" id="input_shipping" class="radio_item_menu">
      <label for="input_shipping" class="label_item_menu">Shipping</label>
     </div>
    </div>
    
    <div id="contentDescription"><p class="testo_scheda">
    This is some text</p>
    </div>
    
    <div id="contentShipping"><p class="testo_scheda">
    This is some other text</p>
    </div>

    For firefox and older browser , inputs need to be adjacent (and ahead in the flow) to the elements to hide (or its parent)

    So for Firefox, at this time, you need to take the input outside their container , so they are adjacent to the element to hide , or at least a parent of these element.

    Firefox version could be

    #input_description:checked~#contentDescription,
    #input_shipping:checked~#contentShipping {
      display: block;
    }
    
    #contentDescription,
    #contentShipping {
      display: none;
    }
    
    .radio_item_menu:checked+.label_item_menu {
      font-weight: bold;
    }
    <input type="radio" name="navbar_menu_store" id="input_description" class="radio_item_menu">
    <label for="input_description" class="label_item_menu">Description</label>
    <br>
    <input type="radio" name="navbar_menu_store" id="input_shipping" class="radio_item_menu">
    <label for="input_shipping" class="label_item_menu">Shipping</label>
    
    
    
    <div id="contentDescription">
      <p class="testo_scheda">
        This is some text</p>
    </div>
    
    <div id="contentShipping">
      <p class="testo_scheda">
        This is some other text</p>
    </div>

    Another option could also be to take the input only outside and recreate them from a pseudo attached to the labels

    Here is another options to keep your containers

    #input_description:checked ~ #contentDescription , 
    #input_shipping:checked ~ #contentShipping  {
        display: block;
    }
    
    #contentDescription, #contentShipping{
      display: none;
    }
    
    .radio_item_menu:checked + .label_item_menu {
      font-weight: bold;
    }
    
    /* hide the radios and create fake ones */
    [type="radio"] {display:none;}
    label {display:inline-block;}
    
    .label_item_menu:before {
      content:'';
      display:inline-block;
      width:10px;
      aspect-ratio:1;
      border-radius:50%;
      border:1px solid;
      vertical-align:middle;
      margin:0 3px;
      color:#555;
    }
    #input_description:checked ~ #radioGroup [for="input_description"]:before , 
    #input_shipping:checked ~ #radioGroup [for="input_shipping"]:before {
        color:blue;
      background: radial-gradient(circle at 50%,  blue 50%,  transparent 50%);
    }
    <!-- hidden radios , adjacent to content to toggle -->
    <input type="radio" name="navbar_menu_store" id="input_description" class="radio_item_menu">
    <input type="radio" name="navbar_menu_store" id="input_shipping" class="radio_item_menu">
    <!-- end adjacent hidden radios -->
    
    <div id="radioGroup"><!-- fake radios drawn aside labels with a pseudo , requires to be styled -->
      <div class="myRadioStyle">
        <label for="input_description" class="label_item_menu">Description</label>
      </div>
      <div class="myRadioStyle">
        <label for="input_shipping" class="label_item_menu">Shipping</label>
      </div>
    </div>
    
    <div id="contentDescription">
      <p class="testo_scheda">
        This is some text</p>
    </div>
    
    <div id="contentShipping">
      <p class="testo_scheda">
        This is some other text</p>
    </div>
    Login or Signup to reply.
  2. You can always use Javascript also. That will allow you to modify your HTML with little changes needed for the javascript to continue to work.

    For my Javascript based answer, I gave your content divs a class called content div that will allow the CSS to easily be modified as well as javascript calls. I also created an active class that changes the display to block.

    Each of the radio buttons I gave a data attribute of target. This will reference the div for that radio.

    Then I simply give each radio a change event listener. And I look for an active div and remove the class then add the active class to the target div for the radio.

    const navbar_menu_store = document.querySelectorAll("[name='navbar_menu_store']");
    
    const changeRadio = (ev) => {
      const hasActive = document.querySelector(".contentDiv.active");
      if(hasActive)hasActive.classList.remove("active")
      
      const el = document.querySelector(ev.target.dataset.target);
      el.classList.add("active")
    };
    
    navbar_menu_store.forEach((i) => i.addEventListener("change",changeRadio))
    .contentDiv{
      display: none;
    }
    
    .contentDiv.active{display:block;}
    
    .radio_item_menu:checked + .label_item_menu {
      font-weight: bold;
    }
    <div id="radioGroup">
     <div class="myRadioStyle">
      <input data-target="#contentDescription" type="radio" name="navbar_menu_store" id="input_description" class="radio_item_menu">
      <label for="input_description" class="label_item_menu">Description</label>
     </div>
     <div class="myRadioStyle">
      <input data-target="#contentShipping" type="radio" name="navbar_menu_store" id="input_shipping" class="radio_item_menu">
      <label for="input_shipping" class="label_item_menu">Shipping</label>
     </div>
    </div>
    
    <div id="contentDescription" class="contentDiv"><p class="testo_scheda">
    This is some text</p>
    </div>
    
    <div id="contentShipping" class="contentDiv"><p class="testo_scheda">
    This is some other text</p>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search