Utilities
Helper functions for setting up components and merging Tailwind classes
To use the utility functions below, install the basic-components[utils]
package into your project. You can also get the code
from GitHub.
uv add "basic-machines[utils]"
JinjaX
Component Directory Structure
Components are organized into subdirectories by type (e.g., accordion
, button
, dialog
).
This organization helps with maintenance but doesn't affect how you use the components in your templates. This allows
you to use components with their original names, without needing to reference the subdirectories.
<!-- Components can be used directly, no need for subdirectory prefixes -->
<Button variant="primary">Click Me</Button>
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
</CardHeader>
</Card>
Basic Components includes a setup_component_catalog()
helper function to include all components in subdirectories.
Each component is assumed to be packaged in a subdirectory within the components
root directory. Components are placed under the
components/ui
top level directory.
project-root
├── components
├── custom
│ ├── CustomComponent.jinja
└── ui
├── ...
├── button
│ └── Button.jinja
├── card
│ ├── Card.jinja
│ ├── CardContent.jinja
│ ├── CardDescription.jinja
│ ├── CardFooter.jinja
│ ├── CardHeader.jinja
│ └── CardTitle.jinja
├── ...
You can place your own components within your own subdirectory also, for example components/custom
. Note that components
should be named uniquely, or JinjaX will load the first one it finds.
from basic_components.utils.jinjax import setup_component_catalog
from starlette.templating import Jinja2Templates
import jinjax
COMPONENT_DIR = "components"
templates = Jinja2Templates(directory="templates")
templates.env.add_extension(jinjax.JinjaX)
catalog = jinjax.Catalog(jinja_env=templates.env)
# include all subdirectories in the JinjaX catalog.
catalog = setup_component_catalog(
catalog, components_dir=COMPONENT_DIR
)
# add any extra dirs to the catalog with custom components
catalog.add_folder("components/custom")
You can get the code for the Jinjax helper from the GitHub repo.
cn()
Basic Components provides a utility function cn()
for merging Tailwind CSS classes while handling conflicts properly.
This needs to be added as a global in the Jinja environment so it is available in all templates.
from starlette.templating import Jinja2Templates
from basic_components.utils.tailwind import tw
templates = Jinja2Templates(directory="templates")
# Add cn to globals
templates.env.globals["cn"] = tw
Usage
The cn()
function is then globally available in templates.
{#def
className: str = ""
#}
<div
class="{{ cn(
'flex flex-col-reverse sm:flex-row sm:space-x-2',
'sm:justify-end' if 'sm:justify-start' not in className else '',
className
) }}"
>
{{ content }}
</div>
Features
- Handles class conflicts (last one wins)
- Supports responsive modifiers (sm:, md:, etc.)
- Supports state modifiers (hover:, focus:, etc.)
- Handles arbitrary values ([...])
- Preserves non-conflicting classes
You can get the code for the tailwind merge from the GitHub repo.
Frameworks
See the examples for setting up a project with FastAPI, Django, or Flask.