Configuration¶
This library is driven almost entirely by render-time options (which framework/theme to target, whether to inline assets, what layout to use) plus field-level UI metadata stored in your model’s JSON Schema.
Rendering entry points¶
submit_url is required for render calls. This library does not default form submit targets.
You can render forms in a few different ways. Pick one that matches your project style:
1) Model-first (recommended)¶
Use FormModel + render_form_html().
from pydantic_schemaforms import Field, FormModel
from pydantic_schemaforms.enhanced_renderer import render_form_html
class RegistrationForm(FormModel):
name: str = Field(..., ui_placeholder="Jane")
email: str = Field(..., ui_element="email")
form_html = render_form_html(
RegistrationForm,
submit_url="/register",
framework="bootstrap",
layout="vertical",
)
If you prefer a method on the model, use RegistrationForm.render_form(...).
2) Builder + handlers (legacy integration)¶
Docs and examples may still reference the builder pattern:
- Build with
create_form_from_model() - Validate + render with
handle_form()/handle_form_async()
This remains supported for backwards compatibility, but the underlying HTML rendering flows through the same enhanced renderer pipeline.
Framework and assets¶
There are two separate but related concepts:
- Framework selection:
framework="bootstrap" | "material" | "none" - Asset delivery: whether the form HTML includes the framework CSS/JS
include_framework_assets¶
False(default): the returned HTML assumes your page already loads Bootstrap/Material.True: the renderer emits framework CSS/JS tags.
asset_mode¶
Controls how the framework assets are provided when include_framework_assets=True:
"vendored": inline the vendored CSS/JS into the output (offline-friendly)."cdn": link to a CDN."none": emit no framework tags.
self_contained¶
For convenience, self_contained=True forces a fully-embedded result:
include_framework_assets=Trueasset_mode="vendored"
html = render_form_html(
RegistrationForm,
submit_url="/register",
self_contained=True,
)
See also: docs/assets.md
Layout selection¶
At the top level, pass layout= to the renderer:
"vertical"(default)"tabbed""side-by-side"
html = render_form_html(RegistrationForm, layout="tabbed", submit_url="/register")
For advanced composition (tabs/accordion/grid wrappers and schema-defined layout fields), see docs/layouts.md.
Field UI metadata¶
UI metadata is stored in json_schema_extra with keys like ui_element, ui_placeholder, etc. The library provides a convenience wrapper pydantic_schemaforms.Field() that populates these keys.
Common UI keys:
ui_element: widget type (see docs/inputs.md)ui_placeholderui_help_textui_options: widget-specific options (e.g. selection choices)ui_class,ui_styleui_disabled,ui_readonly,ui_hidden,ui_autofocusui_order: field ordering
Example:
class ProfileForm(FormModel):
bio: str = Field(
"",
title="Bio",
description="A short bio shown publicly",
ui_element="textarea",
ui_placeholder="Tell us about yourself…",
ui_options={"rows": 6},
ui_order=10,
)
Escaping and templates (|safe)¶
- If you return the HTML string directly from a framework response (e.g. FastAPI
HTMLResponse), no extra escaping happens. - If you embed the HTML into a Jinja template, you must mark it safe:
{{ form_html | safe }}
Otherwise Jinja will escape the markup and you’ll see literal <div> tags in the browser.
Error rendering behavior¶
When you pass errors= to render_form_html() / render_form_html_async(), the renderer now includes a built-in top-level summary block inside form_html.
- Field paths are humanized for users (example:
pets[7].name→Pet #8 — Name). - The same behavior works for Bootstrap and Material output.
- No template-side error loop is required for standard usage.
This means most templates only need:
{{ form_html | safe }}
Layout support behavior¶
The enhanced renderer injects a small internal style block to keep nested/layout-heavy forms (layout, model_list, tabbed/side-by-side structures) width-safe across host templates.
- This reduces the need for route-specific template CSS hacks.
- If your app provides strict custom CSS, you can still override these classes in your host stylesheet.