0

In a Flask app with the Bootstrap-Flask extension, how would one override the default style using WTForms' render_kw class parameter when the form's HTML is automatically rendered using render_form()? [*]

I have this simple Form defined that provides a button to confirm the deletion of a database record, and I'd like that button to be red instead of the standard grey color:

class DeleteMappingForm(FlaskForm):
    submit = SubmitField(_l('Delete mapping'))

The auto-generated HTML (focusing just on the <input> element) is:

<input class="btn btn-secondary btn-md" id="submit" name="submit" type="submit" value="Delete mapping">

I'd like to use the btn-alert instead of the default btn-secondary Bootstrap class to display the button in red instead of grey. The WTForms way of defining "keywords that will be given to the widget at render time" is to pass those as a dict in render_kw. That works fine to add new keywords, but it doesn't replace existing, which I tried doing like this:

class DeleteMappingForm(FlaskForm):
    submit = SubmitField(_l('Delete mapping'), render_kw={'class':'btn btn-alert btn-md'})

That ends up adding the CSS classes I defined to the list of pre-defined CSS classes, ending up with this HTML:

<input class="btn btn-secondary btn-md btn btn-alert btn-md" id="submit" name="submit" type="submit" value="Delete mapping">

Is there a way to have the values passed via render_kw to override the default classes, and have just class="btn btn-alert btn-md"?

Extra information

Looking at how render_kw is handled by WTForms, it seems the values should be overriden (dict gets concatenated, which overrides the same keys, eg.:

>>> a={"class":"abc", "other":"aaa"}
>>> a
{'class': 'abc', 'other': 'aaa'}
>>> b={"class":"def", "other":"aaa"}
>>> b
{'class': 'def', 'other': 'aaa'}
>>> dict(a, **b)
{'class': 'def', 'other': 'aaa'}

I couldn't also identify a source of this in Bootstrap-Flask's handling of render_form()...

[*] I'm using the Bootstrap-Flask extension instead of the original Flask-Bootstrap because the latter unfortunately doesn't support Bootstrap 4+. render_form() is the Bootstrap-Flask equivalent of Flask-Bootstrap's quick_form().

Emilien
  • 2,971
  • 2
  • 22
  • 32

1 Answers1

1

Turns out the solution is to be found on the side of Bootstrap-Flask, and that it already provides a button_style parameter to the render_form macro, allowing to pass a Bootstrap class directly.

The following template gets me that red button I was looking for ;) As easy as that...

{% extends "base.html" %}
{% import 'bootstrap/form.html' as wtf %}

{% block app_content %}
    <h1>{{ title }}</h1>
    <div class="row">
        <div class="col-lg-8">
            {{ wtf.render_form(form, button_style="danger") }}
        </div>
    </div>
{% endblock %}

Well, that is kind of embarrassing - but I'm happy nonetheless to have found the solution, too bad for the time spent writing up this question, but as this might help others with the same challenge I'm adding my answer here.

Emilien
  • 2,971
  • 2
  • 22
  • 32
  • P.S. Check out the [Form Button Customization](https://bootstrap-flask.readthedocs.io/en/stable/advanced.html#form-button-customization) section in docs, there are also some configuration variables that can be used to set the default size/style of buttons. – Grey Li Apr 13 '21 at 04:26