Rendering a radio button list with jQuery Mobile is pretty easy: you just write a normal radio buttons list, apply the jQuery Mobile data attribute and you a get nice mobile “touch” friendly radio button list.


Also having it send back to a knockout.js variable the value of the selection is easy too: just apply the checked binding to the radio button.

Standard Radio Button List with jQuery Mobile and Knockout.js

This was the code that turns a normal radio button list to the jQuery Mobile horizontal group with binding to a Knockout.js variable.

<fieldset data-role="controlgroup" data-type="horizontal">
    <input type="radio" value="Yes" name='Vote'
      data-bind="checked: Vote" />Yes</label>
    <input type="radio" value="No" name='Vote'
      data-bind="checked: Vote" />No</label>
    <input type="radio" value="Abstain" name='Vote'
      data-bind="checked: Vote" />Abstain</label>

<script type="text/javascript">
    viewModel = {
        Vote: ko.observable('Yes')


You can see radio button list at work on this jsfiddle:

Unfortunately this code only works in one direction: from the html control to the variable. It doesn’t work the other way around. I’ve explained the reason why in my previous blog post about how to 2-way bind a jquery mobile flip switch to a knockout.js variable. The solution to the problem is also the same as with the flip switch: a custom binding is needed in order to let knockout.js know how to update the UI of the radio button list when the bound variable changes value.

Custom binding for radio button

In reality the custom binding is not applied to the radio buttons but to the control group that contains them. Let’s first see the code and then I’ll explain what it does. You can see it working on:

ko.bindingHandlers.jqCheckboxRadio = {
    init: function(element, valueAccessor) {
        var currentValue = valueAccessor();
        $(element).attr("data-role", "controlgroup");
        $( "input[type='radio']",element).on( "checkboxradiocreate",
            function( event, ui ) {$(element).data( "init", true )} );
    update: function(element, allBindingsAccessor) {
        var currValue = allBindingsAccessor().value();
        var initialized = $(element).data( "init");
            $("input[type='radio']",element).prop( "checked", false )
                .checkboxradio( "refresh" );
                .prop( "checked", true ).checkboxradio( "refresh" );

Compared to the one for the flip switch, this binding is a bit easier, but has to work-around a bug in the jQuery Mobile API for the controlgroup widget.

The init method

The init method creates the control group via API by calling the .controgroup method, with the options specified in the binding (for ex to make it horizontal, or mini). The next line, which applies the data-role attribute again is to work-around a bug that wouldn’t render rounded corners.

The last line of the init method is needed to keep track of when all radio buttons inside the control group are initialized, otherwise the update method will fail if it’s called before they have been initialized: this is done by registering a callback on the checkboxradiocreate event of the checkboxradio jQuery Mobile widget.

The update method

This method is a bit more straightforward: it just verifies that the radio buttons are initialized, resets all their checked property to false (to account for when the value of the variable is undefined) and then “checks” the radio button whose value matches the value of the bound variable.

Applying the binding to the html radio buttons

Last step is applying the binding to the html code.

<fieldset data-bind="value: Vote, jqCheckboxRadio: { mini: 'true', type: 'horizontal' }">
    <label><input type="radio" value="Yes" name='VoteGroup'
        data-bind="checked: Vote" />Yes</label>
    <label><input type="radio" value="No" name='VoteGroup'
        data-bind="checked: Vote" />No</label>
    <label><input type="radio" value="Abstain" name='VoteGroup'
        data-bind="checked: Vote" />Abstain</label>

Complete demo

You can view the complete demo, where you can see how one version of the control only works in one direction, while the one with the custom binding works also in the other, on the jsfiddle: