javascripthtmlwidgetbalsamiq

Which HTML/JS widget to display this balsamiq control?


I did mockups in balsamiq & they have this nice widget, which

Example: Widget

What the options to implement a widget similar to shown in picture via HTML/CSS & JS?


Solution

  • The approach I present below iterates through all fieldset elements, and if all the inputs therein are of type="radio", hides them and appends span elements (of class="buttonRadio") in their place, using the text from their relevant label elements. It also binds click events to the appended span elements, and triggers the change event on the original inputs and also adds the 'checked' class-name to the clicked/touched element, while removing that class it from its siblings:

    $('fieldset').each(
        function() {
            var legend = $(this).find('legend').text();
            if ($(this).find('input').length == $(this).find('input[type="radio"]').length) {
                var that = $(this),
                    len = that.find('input[type="radio"]').length;
                for (var i = 0; i < len; i++) {
                    $('<span />')
                        .text($('label')
                              .eq(i).text())
                        .addClass('buttonRadio')
                        .attr('data-fromID',that.find('input:eq(' + i + ')').attr('id'))
                        .appendTo(that);
                }
            }
        }).on('click','.buttonRadio',function(){
            var id = $(this).attr('data-fromID');
            $(this).addClass('checked').siblings().removeClass('checked');
            $('#' + id).click().trigger('change');
        }).find('label, input[type="radio"]').css('display','none');​
    

    This uses the following CSS to style those elements:

    .buttonRadio {
        background-color: #fff;
        padding: 0.5em 1em;
        border: 1px solid #000;
        margin: 0.5em 0 0 0;
    }
    
    .buttonRadio.checked {
        background-color: #ffa;
    }​
    

    JS Fiddle demo.


    Edited to amend the jQuery a little:

    1. cached the $(this) object a little earlier in this version,
    2. remembered to use the legend variable that I assigned in the first incarnation but forgot to actually use...sigh.
    3. also hid the actual <legend></legend> element:

      $('fieldset').each(
          function() {
              var that = $(this),
                  legend = that.find('legend').text();
              $('<span />').text(legend).addClass('legend').appendTo(that);
              if (that.find('input').length == that.find('input[type="radio"]').length) {
                  var len = that.find('input[type="radio"]').length;
                  for (var i = 0; i < len; i++) {
                      $('<span />')
                          .text($('label')
                            .eq(i).text())
                          .addClass('buttonRadio')
                          .attr('data-fromID',that.find('input:eq(' + i + ')').attr('id'))
                          .appendTo(that);
                  }
              }
          }).on('click','.buttonRadio',function(){
              var id = $(this).attr('data-fromID');
              $(this).addClass('checked').siblings().removeClass('checked');
              $('#' + id).click().trigger('change');
          }).find('label, input[type="radio"], legend').css('display','none');​
      

    JS Fiddle demo.

    References: