Skip to content

Commit

Permalink
rendering labels and description with classes
Browse files Browse the repository at this point in the history
  • Loading branch information
PanderMusubi committed Dec 31, 2023
1 parent e048e1a commit b0f21cf
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 18 deletions.
28 changes: 28 additions & 0 deletions docs/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,34 @@ Bootstrap-Flask, simply use the built-in class ``SwitchField()`` instead of
``BooleanField()``. See also the example application.


.. _inputcustomization:

Form Input Customization
------------------------

Rendering Label
~~~~~~~~~~~~~~~

Bootstrap offers control for rendering
`text <https://getbootstrap.com/docs/5.3/utilities/text/>`_. This is supported
for inputs of a form by adding ``render_kw={'label_class': '... ...'}`` to the
field constructor. In order to control the rendering of the label of a field,
use ``render_kw={'label_class': '... ...'}``. See also the example application.

Rendering Radio Label
~~~~~~~~~~~~~~~~~~~~~

Similar support exists for the rendering of the labels of options of a
``RadioField()` with ``render_kw={'radio_class': '... ...'}``. See also the
example application.

Rendering Description
~~~~~~~~~~~~~~~~~~~~~

Use ``render_kw={'descr_class': '... ...'}`` for controlling the rendering of a
field's description. See also the example application.


.. _bootswatch_theme:

Bootswatch Themes
Expand Down
2 changes: 1 addition & 1 deletion docs/macros.rst
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ API
form group classes, it will read the config ``BOOTSTRAP_FORM_GROUP_CLASSES`` first
(the default value is ``mb-3``).

.. tip:: See :ref:`button_customization` and :ref:`checkbox_customization` to learn more on customizations.
.. tip:: See :ref:`button_customization`, :ref:`checkbox_customization` and :ref:`input_customization` to learn more on customizations.


render_form()
Expand Down
30 changes: 23 additions & 7 deletions examples/bootstrap5/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@

class ExampleForm(FlaskForm):
"""An example form that contains all the supported bootstrap style form fields."""
date = DateField(description="We'll never share your email with anyone else.") # add help text with `description`
datetime = DateTimeField(render_kw={'placeholder': 'this is a placeholder'}) # add HTML attribute with `render_kw`
date = DateField()
datetime = DateTimeField(render_kw={'placeholder': 'this is a placeholder', 'class': 'fst-italic'})
datetime_local = DateTimeLocalField()
time = TimeField()
time = TimeField(description="This isn't shared", render_kw={'descr_class': 'fs-1 text-decoration-underline'})
month = MonthField()
color = ColorField()
floating = FloatField()
Expand All @@ -45,7 +45,7 @@ class ExampleForm(FlaskForm):
url = URLField()
telephone = TelField()
image = FileField(render_kw={'class': 'my-class'}, validators=[Regexp('.+\.jpg$')]) # add your class
option = RadioField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
option = RadioField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')], render_kw={'label_class': 'text-decoration-underline', 'radio_class': 'text-decoration-line-through'})
select = SelectField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
select_multiple = SelectMultipleField(choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')])
bio = TextAreaField()
Expand All @@ -56,16 +56,30 @@ class ExampleForm(FlaskForm):
submit = SubmitField()


class ExampleFormInline(FlaskForm):
"""An example inline form."""
option = RadioField(description='Choose one', choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')], render_kw={'radio_class': 'text-decoration-line-through', 'descr_class': 'fw-bold'})
submit = SubmitField()


class ExampleFormHorizontal(FlaskForm):
"""An example horizontal form."""
floating = FloatField(description='a float', render_kw={'label_class': 'text-decoration-underline'})
integer = IntegerField(description='an int', render_kw={'descr_class': 'text-decoration-line-through'})
option = RadioField(description='choose 1', choices=[('dog', 'Dog'), ('cat', 'Cat'), ('bird', 'Bird'), ('alien', 'Alien')], render_kw={'label_class': 'text-decoration-underline'})
submit = SubmitField()


class HelloForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(1, 20)])
password = PasswordField('Password', validators=[DataRequired(), Length(8, 150)])
remember = BooleanField('Remember me')
remember = BooleanField('Remember me', description='Rember me on my next visit', render_kw={'descr_class': 'fw-bold text-decoration-line-through'})
submit = SubmitField()


class ButtonForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(1, 20)])
confirm = SwitchField('Confirmation')
confirm = SwitchField('Confirmation', description='Are you sure?', render_kw={'label_class': 'font-monospace text-decoration-underline'})
submit = SubmitField()
delete = SubmitField()
cancel = SubmitField()
Expand Down Expand Up @@ -190,7 +204,9 @@ def test_form():
contact_form=ContactForm(),
im_form=IMForm(),
button_form=ButtonForm(),
example_form=ExampleForm()
example_form=ExampleForm(),
inline_form=ExampleFormInline(),
horizontal_form=ExampleFormHorizontal()
)


Expand Down
8 changes: 8 additions & 0 deletions examples/bootstrap5/templates/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ <h2>Example Form</h2>
submit = SubmitField()</pre>
{{ render_form(example_form) }}

<h2>Inline form</h2>
<pre>{% raw %}{{ render_form(inline_form, form_type='inline') }}{% endraw %}</pre>
{{ render_form(inline_form, form_type='inline') }}

<h2>Horizontal form</h2>
<pre>{% raw %}{{ render_form(horizontal_form, form_type='horizontal') }}{% endraw %}</pre>
{{ render_form(horizontal_form, form_type='horizontal') }}

<h2>Render a form with render_form</h2>
<pre>{% raw %}{{ render_form(form) }}{% endraw %}</pre>
{{ render_form(form) }}
Expand Down
50 changes: 40 additions & 10 deletions flask_bootstrap/templates/bootstrap5/form.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@

{% set form_group_classes = form_group_classes or config.BOOTSTRAP_FORM_GROUP_CLASSES %}

{# support for label_class and descr_class which are popped, to prevent they are added to input, but restored at the end of this macro for the next rendering #}
{%- set label_class = '' -%}
{%- if field.render_kw.label_class -%}
{% set label_class = field.render_kw.pop('label_class', '') -%}
{% set label_classes = ' ' + label_class -%}
{%- endif -%}
{%- set radio_class = '' -%}
{%- if field.render_kw.radio_class -%}
{% set radio_class = field.render_kw.pop('radio_class', '') -%}
{% set radio_classes = ' ' + radio_class -%}
{%- endif -%}
{%- set descr_class = '' -%}
{%- if field.render_kw.descr_class -%}
{% set descr_class = field.render_kw.pop('descr_class', '') -%}
{% set descr_classes = ' ' + descr_class -%}
{%- endif -%}

{# combine render_kw class or class/class_ argument with Bootstrap classes #}
{% set render_kw_class = ' ' + field.render_kw.class if field.render_kw.class else '' %}
{% set class = kwargs.pop('class', '') or kwargs.pop('class_', '') %}
Expand All @@ -68,14 +85,14 @@
{%- else -%}
{{ field(class="form-check-input%s" % extra_classes, **field_kwargs)|safe }}
{%- endif %}
{{ field.label(class="form-check-label", for=field.id)|safe }}
{{ field.label(class="form-check-label%s" % label_classes, for=field.id)|safe }}
{%- if field.errors %}
{%- for error in field.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{%- endfor %}
{%- elif field.description -%}
{% call _hz_form_wrap(horizontal_columns, form_type, required=required) %}
<small class="form-text text-body-secondary">{{ field.description|safe }}</small>
<small class="form-text text-body-secondary{{ descr_classes|safe }}">{{ field.description|safe }}</small>
{% endcall %}
{%- endif %}
</div>
Expand All @@ -85,12 +102,13 @@
this is just a hack for now, until I can think of something better #}
<div class="{{ form_group_classes }} {% if form_type == 'horizontal' %}row{% endif %}{% if required %} required{% endif %}">
{%- if form_type == "inline" %}
{{ field.label(class="visually-hidden")|safe }}
{{ field.label(class="visually-hidden%s" % label_classes)|safe }}
{% elif form_type == "horizontal" %}
{{ field.label(class="col-form-label" + (
" col-%s-%s" % horizontal_columns[0:2]))|safe }}
" col-%s-%s" % horizontal_columns[0:2]) + (
"%s" % label_classes))|safe }}
{%- else -%}
{{ field.label(class="form-label")|safe }}
{{ field.label(class="form-label%s" % label_classes)|safe }}
{% endif %}
{% if form_type == 'horizontal' %}
<div class="col-{{ horizontal_columns[0] }}-{{ horizontal_columns[2] }}">
Expand All @@ -99,7 +117,7 @@
{% for item in field -%}
<div class="form-check{% if form_type == "inline" %} form-check-inline{% endif %}">
{{ item(class="form-check-input")|safe }}
{{ item.label(class="form-check-label", for=item.id)|safe }}
{{ item.label(class="form-check-label%s" % radio_classes, for=item.id)|safe }}
</div>
{% endfor %}
{#% endcall %#}
Expand All @@ -111,7 +129,7 @@
<div class="invalid-feedback d-block">{{ error }}</div>
{%- endfor %}
{%- elif field.description -%}
<small class="form-text text-body-secondary">{{ field.description|safe }}</small>
<small class="form-text text-body-secondary{{ descr_classes|safe }}">{{ field.description|safe }}</small>
{%- endif %}
</div>
{%- elif field.type == 'SubmitField' -%}
Expand Down Expand Up @@ -166,7 +184,9 @@
{% endif %}
{%- endif %}
{% elif form_type == "horizontal" %}
{{ field.label(class="col-form-label" + (" col-%s-%s" % horizontal_columns[0:2]))|safe }}
{{ field.label(class="col-form-label" + (
" col-%s-%s" % horizontal_columns[0:2]) + (
"%s" % label_classes))|safe }}
<div class="col-{{ horizontal_columns[0] }}-{{ horizontal_columns[2] }}">
{%- if field.type in ['DecimalRangeField', 'IntegerRangeField'] %}
{% if field.errors %}
Expand Down Expand Up @@ -196,7 +216,7 @@
{%- endfor %}
{%- elif field.description -%}
{% call _hz_form_wrap(horizontal_columns, form_type, required=required) %}
<small class="form-text text-body-secondary">{{ field.description|safe }}</small>
<small class="form-text text-body-secondary{{ descr_classes|safe }}">{{ field.description|safe }}</small>
{% endcall %}
{%- endif %}
{%- else -%}
Expand Down Expand Up @@ -225,11 +245,21 @@
<div class="invalid-feedback d-block">{{ error }}</div>
{%- endfor %}
{%- elif field.description -%}
<small class="form-text text-body-secondary">{{ field.description|safe }}</small>
<small class="form-text text-body-secondary{{ descr_classes|safe }}">{{ field.description|safe }}</small>
{%- endif %}
{%- endif %}
</div>
{% endif %}

{%- if label_class -%}
{%- set _ = field.render_kw.update({'label_class': label_class}) -%}
{%- endif -%}
{%- if radio_class -%}
{%- set _ = field.render_kw.update({'radio_class': radio_class}) -%}
{%- endif -%}
{%- if descr_class -%}
{%- set _ = field.render_kw.update({'descr_class': descr_class}) -%}
{%- endif -%}
{% endmacro %}

{# valid form types are "basic", "inline" and "horizontal" #}
Expand Down

0 comments on commit b0f21cf

Please sign in to comment.