Align radio buttons horizontally in django forms

HI

I want to align the radio buttons horizontally. By default django forms displays in vertical format.

feature_type  = forms.TypedChoiceField(choices = formfields.FeatureType, widget = forms.RadioSelect)

Is there any special parameter that we can pass for radio buttons alignment?

Thanks in advance


Thats the behavior of the RadioField. If you want it rendered horizontally, create a horizontal renderer, like something as follows:

from django.utils.safestring import mark_safe

class HorizontalRadioRenderer(forms.RadioSelect.renderer):
  def render(self):
    return mark_safe(u'\n'.join([u'%s\n' % w for w in self]))


class ApprovalForm(forms.Form):
    approval = forms.ChoiceField(choices=APPROVAL_CHOICES,
                 initial=0,
                 widget=forms.RadioSelect(renderer=HorizontalRadioRenderer),
                                 )

Another way out is to changing the style of ul->li list to display:inline-block. You can do something like that

 <style>
 ul#youelementId li{
  display: inline-block;
  }
</style>

hope this would help next reader.


I've come up with an alternative solution. If you are using bootstrap to render your forms, you can add the .form-check-inline class to the input and the field will display horizontally. Listed below is code that shows what I'm describing. I hope this helps someone from reinventing the wheel. Thanks for reading. Take care and have a good day.

                feature_type = forms.MultipleChoiceField(
                required=False,
                ...
                widget=forms.CheckboxSelectMultiple(attrs={'class': 'form-check-inline'})
                )

This image shows a set of radio buttons displayed horizontally.


On my Django 2.2.6 above solutions did not worked well, so I post my solution after many tries and following the breadcrumbs until the django forms widget templates used.

I had to override 2 templates, and heritage my own widget class and then point it.

The modified default django templates have been:

  • django/forms/templates/django/forms/widgets/input_option.html
  • django/forms/templates/django/forms/widgets/multiple_input.html

Now they are:

PROJECT_NAME/PROJECT_APP/templates/admin/horizontal_option.html

{% if widget.wrap_label %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %} class="radio-inline">{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>{% endif %}

PROJECT_NAME/PROJECT_APP/templates/admin/horizontal_radios.html

{% with id=widget.attrs.id %}<ul{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %}
  <li>{{ group }}
    <ul{% if id %} id="{{ id }}_{{ index }}"{% endif %}>{% endif %}{% for option in options %}
    {% include option.template_name with widget=option %}{% endfor %}{% if group %}
  </ul></li>{% endif %}{% endfor %}
</ul>{% endwith %}
  • The first one includes a hardcoded class: class="radio-inline" at labels, which in default Django had nothing
  • The second one the rendering of the set of radios, I removed the extra HTML li tags they were rendered inside the internal ul tag.

Then you need to create your own widget class:

from django.forms import RadioSelect


class HorizontalRadioSelect(RadioSelect):
    template_name = 'admin/horizontal_radios.html'
    option_template_name = 'admin/horizontal_inputs.html'

And finally, in my case, I pointed to it overriding formfield_overrides class attribute in my admin. But you can do this in your models too I think:

    formfield_overrides = {
        models.BooleanField: {'widget': HorizontalRadioSelect(choices=[(True, "Yes"), (False, "No"), (None, "Unknown")],)},
    }