Quickstart
Install Formidable¶
Run the following command:
pip install formidable
uv add formidable
Create a form¶
Create a new file in your project, typically inside a forms folder:
import formidable as f
class TeamForm(f.Form):
name = f.TextField()
description = f.TextField(required=False)
In the Controller/View¶
Add the form to your controller in your framework of choice. Here's an example using Flask:
from flask import Flask, request, render_template
from .forms.team import TeamForm
app = Flask(__name__)
@app.route("/teams/new", methods=["GET"])
def index():
form = TeamForm()
return render_template("teams/new.html", form=form)
In the Templates¶
Now let's look at the template side.
Render helpers
Formidable fields provide helper functions to simplify HTML generation. These helpers are practical but entirely optional. Compare the two approaches:
Without helper functions (standard HTML):
<div class="form-field">
<label for="{{ form.field.id }}">My label</label>
<input type="text"
id="{{ form.field.id }}"
name="{{ form.field.name }}"
value="{{ form.field.value }}"
/>
{% if form.field.error -%}
<span class="field-error">{{ form.field.error_message }}</span>
{%- endif %}
</div>
with helper functions:
<div class="form-field">
{{ form.field.label("My label") }}
{{ form.field.text_input() }}
{{ form.field.error_tag() }}
</div>
You can read more about these render methods in the Fields page.
Here is the teams/new.html template, which takes advantage of the helpers:
<form method="POST" action="/teams/create">
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
<div class="field">
{{ form.name.label("Name") }}
{{ form.name.text_input() }}
{{ form.name.error_tag() }}
</div>
<div class="field">
{{ form.description.label("Description") }}
{{ form.description.textarea() }}
{{ form.description.error_tag() }}
</div>
<button type="submit">Create</button>
</form>

Validate the Form¶
When the user submits the form, process the information like this:
@app.route("/teams/create", methods=["POST"])
def create():
form = TeamForm(request.form)
if form.is_invalid(): # or `if not form.is_valid`
# There is an error, so re-render the form
# with the submitted values and error messages
return render_template("teams/new.html", form=form)
# Form is valid, proceed with saving
data = form.save()
create_team(**data)
flash("Team created")
return redirect(url_for("index"))
This demonstrates the basic pattern for handling forms with Formidable. For more advanced features, customization options, and additional field types, continue reading the documentation.