Previous: Publishing | Next: Architecture
This document explains how to add a new source plugin to nicegui-builder.
A plugin lets the library understand a new source type and translate it into:
- form-oriented specs
- collection-oriented specs
- default widgets
- optional rich rendering behaviors
Examples already present in the project:
pydanticfor schema-driven formspandasfor table-oriented collections
The core library should stay source-agnostic. A plugin is responsible for understanding a specific source and producing core-friendly specs.
Typical pipeline:
source -> plugin inspection -> specs -> widget resolution -> layout/rendering
There are currently two practical plugin families.
Field plugins power form(...).
They typically implement:
supports(source)inspect_fields(source)build_layout(source, flavor="")build_field_context(model_class, model_instance, fieldname)resolve_field_node(model_class, model_instance, fieldname, value)resolve_widget(spec, variant="std")- optional
render_form(source, flavor="")
See src/nicegui_builder/plugins/base.py.
Collection plugins power table(...).
They typically implement:
supports(source)inspect_collection(source)resolve_collection_widget(spec, variant="std")- optional
render_collection(source, spec, variant="std")
Plugins are registered in the global plugin registry.
Minimal pattern:
from nicegui_builder.plugins.registry import plugin_registry
class MyPlugin:
name = "my_plugin"
def supports(self, source) -> bool:
...
my_plugin = MyPlugin()
plugin_registry.register(my_plugin)Built-in plugins are typically registered from their package __init__.py.
Your plugin should produce FieldSpec values rich enough to support:
- automatic widget choice
- labels and descriptions
- defaults
- validation constraints
- choices
- plugin-specific metadata in
source_meta
Your plugin should produce a CollectionSpec that describes:
- columns
- optional filter metadata
- source-level metadata
Keep it strict and predictable.
If the plugin cannot fully support the source, return False.
Prefer putting source understanding into FieldSpec and CollectionSpec instead of mixing it directly into rendering code.
A plugin should usually have a dedicated resolution step from spec to widget intent.
For example:
- YAML map for defaults
- Python heuristics for richer cases
Most plugins should let the generic builder do the rendering.
Use render_form(...) or render_collection(...) only for behaviors that are meaningfully richer than generic rendering.
Current example:
- the
pandasplugin usesrender_collection(..., variant="filters")for a richer filter UI
The pydantic plugin is a good reference for form-oriented plugins.
Its code is organized under:
src/nicegui_builder/plugins/pydantic/inspect.pysrc/nicegui_builder/plugins/pydantic/mapping.pysrc/nicegui_builder/plugins/pydantic/resolve.pysrc/nicegui_builder/plugins/pydantic/plugin.pysrc/nicegui_builder/plugins/pydantic/pydantic-nicegui.yml
The YAML file is plugin-local on purpose, so the plugin stays self-contained.
One useful pattern in the pydantic plugin is the datetime split field.
The resolver keeps date_input and time_input grouped as one logical field, while still allowing the layout node to override the wrapper container.
Example:
- field__starts_at:
container: column
classes: gap-2This means the plugin can provide a rich field expansion without forcing a single visual wrapper such as row.
The pandas plugin is a good reference for collection-oriented plugins.
It shows how to:
- inspect a
DataFrame - infer column/filter metadata
- provide default table widgets
- optionally render a richer filtered table variant
See:
A plugin should usually be tested at three levels:
supports(...)- spec generation
- public entry point integration through
form(...)ortable(...)
Good tests are usually small and structural. You do not need a full NiceGUI runtime for most plugin tests.
- Keep the core source-agnostic.
- Prefer specs over ad hoc dictionaries.
- Use
source_metafor plugin-specific metadata. - Keep plugin-local maps and heuristics inside the plugin package.
- Favor small rich render variants over plugin-wide custom rendering.
- Preserve compatibility with the stable top-level API.
Likely good additions:
dataclassesjson_schemasqlmodelsqlalchemypolars
sqlmodel is especially interesting if the project later grows stronger persistence-aware CRUD workflows.