Search code examples
htmlblazorradio-button

How do I select a radio button by clicking on a div in Blazor?


In my project i have a couple of radio button groups where they have some extra information attached to them as you can see here:

    <div>
        <div class="option">
            <input type="radio" name="Letters" value="a" />
            <a>Letter A</a>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        </div>
        <div class="option">
            <input type="radio" name="Letters" value="b" />
            <a>B</a>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        </div>
        <div class="option">
            <input type="radio" name="Letters" value="c" />
            <a>C</a>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        </div>
        <div class="option">
            <input type="radio" name="Letters" value="d" />
            <a>D</a>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        </div>
    </div>

It works if i click on the radio button dot, but I want to be able to click on the parent div and change the value. I read that this can be done via @onchanged on the parent div, but I've only encountered JS snippets of how to do it.

How would I do this?


Solution

  • You could use <label> elements instead of <div> elements to propagate the click event to the inputs. No code required!

    <label class="option">
        <input type="radio" name="Letters" value="c" />
        <a>C</a>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
    </label>
    

    From the docs:

    Alternatively, you can nest the <input> directly inside the <label>, in which case the for and id attributes are not needed because the association is implicit:

    Demo

    https://blazorfiddle.com/s/sr414t1n

    Note: I have added a little bit of CSS to the .option class to render labels as block elements. The hover styling is just to show when the click will have an effect on the <label> elements.

    .option {
      display: block;
    }
    .option:hover {
      background-color: #ccc;
      cursor: pointer;
    }
    

    Caveat

    Note: strictly speaking, placing block elements inside inline elements is not allowed/recommended. Your dev pipeline / coding standards may or may not allow you to place a <p> inside a <label>.

    State-bound styling

    To style the outer label you could bind to a property that stores the selected option and then set a class based on that.

    I have created a new demo showing this: https://blazorfiddle.com/s/56k8tfav.

    I have created a RadioOption class to represent each radio option. I am then setting the selected option in the local Selected property in the @onchange event handler. This can be used for setting the selected CSS class on the relevant option.

    This is just a pretty quick mockup to demonstrate one approach - you can choose to implement in whatever way you prefer.

    @foreach (var option in Options)
    {
        <label class="option @(Selected == option ? "selected" : null)">
            <input type="radio" name="Letters" value="@option.Value" 
                   @onchange="@(() => Selected = option)" />
            <a>@option.Label</a>
            <p>@option.Text</p>
        </label>
    }
    

    (Edit: the CSS solution posted on your other question uses the :has CSS selector and is a cleaner implementation from a pure CSS point of view. You still might want to use my technique for cleaning your markup).