evenly spaced, horizontal radio buttons with labels underneath

776 Views Asked by At

For a user form I need several likert items. (Questions to assess the degree of an opinion. Example at the bottom)
I'm required to use the oTree library, which heavily builds on django. A solution that deviates from oTree as little as possible is desirable.

The RadioSelectHorizontal widget seems like the obvious choice here. But two differences to the default are mandatory:

  1. the option labels ("agree", "neutral", etc.) have to be positioned just underneath the radio buttons.
  2. the radio buttons have to be evenly spaced. (Ideally, they are aligned across the entire page)


In contrast, the default look will have the labels between the radio buttons and allow only as little space as each label needs:


enter image description here


The code:

question_1 = models.IntegerField(widget=widgets.RadioSelectHorizontal, 
                                 label="some question", 
                                 choices=[[1, "strongly disagree"], [2, "disagree"], [3, "neutral"], [4, "agree"], [5, "strongly agree"]])


How can I approach this?

django documentation mentions several approachs, i.e. custom widgets, custom CSS and more. But as far as I can tell, oTree is a bit more limited than django.


For illustration an example that meets both requirements:


enter image description here

1

There are 1 best solutions below

0
On

You need to do a couple things before getting this right. This solution works for labels aligned above or below the button.

First, you need containers to place the question, the labels and the buttons. I am following the ideas laid out in this reference question. In my case I needed every question inside a table, and every button inside a td for alignment purposes.

table.TheTable td.buttonGroup{
    width: 70px;
    display: inline-block;
}

div .labelWrap{
    display: block;
    text-align: center;
    margin: 0 0.2em;
}

div .buttonWrap {
    display: block;
    text-align: center;
    margin: 0.5em auto;
}

Once you have that, bear in mind that you have to place the formfields individually, and that you have to control for the label and the button separately.

<table>
  {{ for field in form }}
    <tr>                
      {{ for choice in field }}
      <td class="buttonGroup">
        <div class="buttonWrap"> {{ choice }} </div>
        <div class="labelWrap"> {{ choice.label }} </div>
      </td>
    </tr>
  {{ endfor }}
</table>

Of course you will need to align and format other things. But I have laid out how to align the labels to the buttons only.