Radio Buttons Controlling Textfields

In a form, how do I have a set of radio buttons with the last one being an other option that shows and hides a textfield depending on if it is selected or not? I have seen how to disable the textfield if the radio button is not selected, but not how to hide it. Is this possible?

Well, it’s a bit tricky and there are a couple ways to do it.

Probably the simplest would just to toggle the CSS display property between “none” and “block” or “inline”. You have to be careful in this case because it will still be submitted with the form.

A slightly better way to do this would be to remove and append an input element. The tricky part about this is that when you remove it, you need to be sure to store it’s value somewhere (or the whole element itself, if you prefer) and add it back when appropriate.

radio button onclick-
-set the textfield “display” style as “none” to hide
-set “display” as “block” or “inline” or “inline-block” to show the textfield based on display behaviour

Do you think changing it’s name and id values would be enough to stop accidental submission?

Typically you would set an onclick event on each radio button in the group. The textfield can have a similar name to the group, so that the script can automatically know which one to affect.

When a radio button is selected, if it’s the one called “other” you remove a “hidden” class name from the text field.
When the radio button is not called “other” you add a “hidden” class name to the text field.

Here are the details.

Start with the basic form.


<form>
    <p>What colour is your cat?</p>
    <p>
        <label><input type="radio" name="catcolor" value="black"> Black</label>
        <label><input type="radio" name="catcolor" value="white"> White</label>
        <label><input type="radio" name="catcolor" value="tabby"> Tabby</label>
        <label><input type="radio" name="catcolor" value="other"> Other</label>
    </p>
    <p id="othercatcolor">Color? <input name="othercatcolor"></p>
    </p>
</form>

When the other color is submitted with no scripting, you can not guarantee that the radio button will be on other. That’s just how things work with no scripting, so it has to be handled properly.
How your server-side script should deal with it is to use the presence of any “othercatcolor” content to determine whether the other situation applies. If it’s empty, the server-side script can use the value from the radio group instead.

Now on with the client-side scripting.

I’ve used an id of “othercatcolor” because the radio group is called “catcolor”. That allows the same scripting code to be used across a wide range of situations.

To try and keep this flexible, we can call a function with the name of the radio group we want to setup.


function initOtherRadio(name) {
    ...
}
initOtherRadio('catcolor');

First we get all of the matching radio elements, and loop through them.


function initOtherRadio(name) {
    var radios = document.getElementsByName(name),
        radio,
        i;
    for (i = 0; i < radios.length; i += 1) {
        ...
    }
}

In the loop we assign to the onclick event of each radio a reference to a function that will handle the click. In this case, that function is going to be called otherRadioHandler

Also, to ensure that the section to be hidden is actually hidden when the page loads, we can have the script click on the first radio button, which will trigger the event handler.


for (i = 0; i < radios.length; i += 1) {
    radio = radios[i];
    radio.onclick = otherRadioHandler;
    
    // select the first one by default, which hides the appropriate field
    if (i === 0) {
        radio.click();
    }
}

The otherRadioHandler() function just needs to check the value attribute. If it’s “other” show the text field. If it’s not, hide it.

We’ll use this CSS to hide things.


.hidden {
    display: none;
}

How does the function know what to hide? If the radio name is “catcolor” the id attribute to affect will be “othercatcolor”


function otherRadioHandler() {
    var other = document.getElementById('other' + this.name);
    if (this.value === 'other') {
        other.className = '';
    } else {
        other.className = 'hidden';
    }
}

And that’s it.

Here’s a simple test page:


<!DOCTYPE HTML>
<html>
<head>
    <title>Show other field</title>
    <link type="text/css" rel="stylesheet" href="style.css">
</head>
<body>
<form>
    <p>What colour is your cat?</p>
    <p>
        <label><input type="radio" name="catcolor" value="black"> Black</label>
        <label><input type="radio" name="catcolor" value="white"> White</label>
        <label><input type="radio" name="catcolor" value="tabby"> Tabby</label>
        <label><input type="radio" name="catcolor" value="other"> Other</label>
    </p>
    <p id="othercatcolor">Color? <input name="othercatcolor"></p>
    </p>
</form>
<script src="script.js"></script>
</body>
</html>

the CSS file

style.css


.hidden {
    display: none;
}

and of course, the script.

script.js


function initOtherRadio(name) {
    function otherRadioHandler() {
        var other = document.getElementById('other' + this.name);
        if (this.value === 'other') {
            other.className = '';
        } else {
            other.className = 'hidden';
        }
    }

    var radios = document.getElementsByName(name),
        radio,
        i;
    for (i = 0; i < radios.length; i += 1) {
        radio = radios[i];
        radio.onclick = otherRadioHandler;
        
        // select the first one by default, which hides the appropriate field
        if (i === 0) {
            radio.click();
        }
    }
}
initOtherRadio('catcolor');

Thank you, that did exactly what I was asking for.