Bootstrap 4 & 5 helper for Flask projects providing Jinja macros for forms, tables, navigation, and utilities.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive form rendering capabilities with Bootstrap styling, supporting multiple layout types, validation error display, field grouping, and extensive customization options for Flask-WTF/WTForms integration.
Render entire forms with Bootstrap styling and automatic validation error handling.
def render_form(form, action="", method="post", extra_classes=None, role="form",
form_type="basic", horizontal_columns=('lg', 2, 10), enctype=None,
button_map={}, button_style="", button_size="", id="",
novalidate=False, render_kw={}, form_group_classes="",
form_inline_classes=""):
"""
Render a complete form with Bootstrap styling.
Args:
form: WTForms form object
action (str): Form action URL (default: current URL)
method (str): HTTP method (default: "post")
extra_classes (str): Additional CSS classes for form element
role (str): ARIA role attribute (default: "form")
form_type (str): Layout type - "basic", "inline", or "horizontal"
horizontal_columns (tuple): Column sizing for horizontal layout (breakpoint, label_cols, field_cols)
enctype (str): Form encoding type (auto-detected for file uploads)
button_map (dict): Custom button styles per field name
button_style (str): Default button style for submit buttons
button_size (str): Default button size for submit buttons
id (str): Form element ID attribute
novalidate (bool): Disable HTML5 validation
render_kw (dict): Additional attributes for form element
form_group_classes (str): Classes for form groups (Bootstrap 5)
form_inline_classes (str): Classes for inline forms (Bootstrap 5)
Returns:
Rendered HTML form with Bootstrap styling
Layout Types:
- basic: Standard vertical form layout
- inline: Horizontal inline form layout
- horizontal: Two-column layout with labels and fields
"""Render individual form fields with Bootstrap styling and validation states.
def render_field(field, form_type="basic", horizontal_columns=('lg', 2, 10),
button_map={}, button_style='', button_size='', form_group_classes=''):
"""
Render an individual form field with Bootstrap styling.
Args:
field: WTForms field object
form_type (str): Layout type - "basic", "inline", or "horizontal"
horizontal_columns (tuple): Column sizing for horizontal layout
button_map (dict): Custom button styles for this field
button_style (str): Default button style for submit/button fields
button_size (str): Default button size for submit/button fields
form_group_classes (str): Additional classes for form group (Bootstrap 5)
Returns:
Rendered HTML field with appropriate Bootstrap classes
Field Type Support:
- Text inputs (StringField, TextAreaField, etc.)
- Select fields (SelectField, SelectMultipleField)
- Boolean fields (BooleanField, SwitchField)
- File uploads (FileField, MultipleFileField)
- Hidden fields (HiddenField)
- Submit buttons (SubmitField)
- Custom field types
Validation Features:
- Automatic validation state classes (is-valid, is-invalid)
- Error message display
- Required field indicators
"""Render multiple fields in a single row using Bootstrap grid classes.
def render_form_row(fields, row_class='row', col_class_default='col',
col_map={}, button_map={}, button_style='', button_size='',
form_group_classes='', form_type='basic',
horizontal_columns=('lg', 2, 10)):
"""
Render multiple form fields in a single row layout.
Args:
fields (list): List of WTForms field objects
row_class (str): CSS class for row container (default: 'row')
col_class_default (str): Default column class (default: 'col')
col_map (dict): Custom column classes per field name
button_map (dict): Custom button styles per field name
button_style (str): Default button style
button_size (str): Default button size
form_group_classes (str): Form group classes (Bootstrap 5)
form_type (str): Form layout type
horizontal_columns (tuple): Horizontal form column configuration
Returns:
Rendered HTML row with fields in Bootstrap grid layout
Example col_map:
{
'first_name': 'col-md-6',
'last_name': 'col-md-6',
'email': 'col-12'
}
"""Render validation errors for hidden form fields.
def render_hidden_errors(form):
"""
Render validation errors for hidden form fields.
Args:
form: WTForms form object
Returns:
Rendered HTML alert with hidden field errors
Used for displaying validation errors from hidden fields like CSRF tokens
that users cannot see but may have validation issues.
"""Custom field type for Bootstrap switch components.
class SwitchField(BooleanField):
"""
A wrapper field for BooleanField that renders as a Bootstrap switch.
Inherits all BooleanField functionality but renders with switch styling
instead of standard checkbox appearance.
"""
def __init__(self, label=None, **kwargs):
"""
Initialize switch field.
Args:
label (str): Field label
**kwargs: Additional field arguments passed to BooleanField
"""Standard vertical form layout with fields stacked vertically.
<!-- Template usage -->
{% from 'bootstrap5/form.html' import render_form %}
{{ render_form(form, form_type="basic") }}
<!-- Rendered output structure -->
<form method="post" role="form">
<div class="mb-3">
<label class="form-label">Username</label>
<input type="text" class="form-control" name="username">
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>Horizontal inline form layout with fields arranged side-by-side.
<!-- Template usage -->
{{ render_form(form, form_type="inline") }}
<!-- Rendered output structure (Bootstrap 5) -->
<form method="post" role="form" class="row row-cols-lg-auto g-3 align-items-center">
<div class="col">
<label class="visually-hidden">Username</label>
<input type="text" class="form-control" name="username" placeholder="Username">
</div>
<div class="col">
<label class="visually-hidden">Password</label>
<input type="password" class="form-control" name="password" placeholder="Password">
</div>
<div class="col">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>Two-column layout with labels and fields in separate columns.
<!-- Template usage -->
{{ render_form(form, form_type="horizontal", horizontal_columns=('lg', 2, 10)) }}
<!-- Rendered output structure -->
<form method="post" role="form">
<div class="row mb-3">
<label class="col-lg-2 col-form-label">Username</label>
<div class="col-lg-10">
<input type="text" class="form-control" name="username">
</div>
</div>
<div class="row mb-3">
<label class="col-lg-2 col-form-label">Password</label>
<div class="col-lg-10">
<input type="password" class="form-control" name="password">
</div>
</div>
<div class="row">
<div class="col-lg-10 offset-lg-2">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>Bootstrap-Flask automatically applies validation classes based on field errors:
<!-- Field with validation error -->
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" class="form-control is-invalid" name="email" value="invalid-email">
<div class="invalid-feedback">
Please enter a valid email address.
</div>
</div>
<!-- Field with valid input -->
<div class="mb-3">
<label class="form-label">Username</label>
<input type="text" class="form-control is-valid" name="username" value="john_doe">
<div class="valid-feedback">
Looks good!
</div>
</div>When a field has multiple validation errors, all are displayed:
<div class="invalid-feedback">
<ul class="mb-0">
<li>This field is required.</li>
<li>Must be between 8 and 150 characters long.</li>
</ul>
</div># forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Length, Email
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(1, 20)])
password = PasswordField('Password', validators=[DataRequired(), Length(8, 150)])
remember = BooleanField('Remember me')
submit = SubmitField('Sign In')<!-- template.html -->
{% from 'bootstrap5/form.html' import render_form %}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6">
<h2>Login</h2>
{{ render_form(form) }}
</div>
</div>
</div>{% from 'bootstrap5/form.html' import render_form %}
{{ render_form(form,
form_type="horizontal",
horizontal_columns=('md', 3, 9),
button_style="success",
button_size="lg",
extra_classes="border p-4 rounded"
) }}{% from 'bootstrap5/form.html' import render_form_row, render_field %}
<form method="post">
{{ form.hidden_tag() }}
<!-- Name fields in one row -->
{{ render_form_row([form.first_name, form.last_name],
col_map={'first_name': 'col-md-6', 'last_name': 'col-md-6'}) }}
<!-- Full-width email field -->
{{ render_field(form.email) }}
<!-- Address fields in one row -->
{{ render_form_row([form.address, form.city, form.zip_code],
col_map={'address': 'col-md-6', 'city': 'col-md-4', 'zip_code': 'col-md-2'}) }}
{{ render_field(form.submit) }}
</form># forms.py
from flask_bootstrap import SwitchField
class SettingsForm(FlaskForm):
notifications = SwitchField('Enable notifications')
dark_mode = SwitchField('Dark mode')
auto_save = SwitchField('Auto-save documents')<!-- Renders as Bootstrap switches -->
{% from 'bootstrap5/form.html' import render_field %}
<div class="form-check form-switch">
{{ render_field(form.notifications) }}
</div># forms.py
from wtforms import FileField
from flask_wtf.file import FileRequired, FileAllowed
class UploadForm(FlaskForm):
file = FileField('Upload File', validators=[
FileRequired(),
FileAllowed(['jpg', 'png', 'pdf'], 'Images and PDFs only!')
])
submit = SubmitField('Upload')<!-- Automatically sets enctype="multipart/form-data" -->
{{ render_form(form) }}{{ render_form(form,
button_map={
'submit': 'btn-success btn-lg',
'cancel': 'btn-outline-secondary',
'delete': 'btn-danger'
}
) }}<!-- Bootstrap 4 -->
{% from 'bootstrap4/form.html' import render_form %}
{{ render_form(form, form_type="inline") }}
<!-- Bootstrap 5 -->
{% from 'bootstrap5/form.html' import render_form %}
{{ render_form(form,
form_type="inline",
form_inline_classes="row row-cols-lg-auto g-3 align-items-center"
) }}The main differences include updated CSS classes, form control styling, and enhanced accessibility features in Bootstrap 5.
Install with Tessl CLI
npx tessl i tessl/pypi-bootstrap-flask