Building Custom Components
Learn how to construct custom reusable UI components and leverage Metupy's dynamic component resolution mechanism.
1. Directory Structure & Naming Rules
Metupy resolves components on-the-fly using components/__init__.py. Create your Python component files directly inside the local components/ directory.
Naming Convention
Class names written in PascalCase automatically map to snake_case filenames.
•
•
•
Badge → components/badge.py•
InfoCard → components/info_card.py2. Creating a Component Class
A Metupy component is simply a Python class that implements the str magic method to return HTML string output:
components/status_badge.py
# components/status_badge.py
class StatusBadge:
def __init__(self, text: str, status: str = "active"):
self.text = text
self.status = status
def __str__(self) -> str:
color = "var(--accent)" if self.status == "active" else "var(--text-muted)"
bg = "var(--accent-glow)" if self.status == "active" else "var(--bg-surface)"
return f'''<span style="
display: inline-flex;
align-items: center;
gap: 6px;
padding: 3px 10px;
font-size: 0.825rem;
font-weight: 600;
border-radius: 20px;
background: {bg};
color: {color};
border: 1px solid var(--border-color);
">
<span style="width: 6px; height: 6px; border-radius: 50%; background: {color};"></span>
{self.text}
</span>'''
3. Importing & Using Custom Components
Once the component file is created, import it directly from components inside any page:
pages/demo.py
# pages/demo.py
from metupy.page import Page
from components import StatusBadge
page = Page(title="Custom Component Demo")
badge = StatusBadge("System Online", status="active")
page.title("System Overview")
page.raw(f"<p>Current status: {badge}</p>")
Styling Best Practice
Always reference Metupy's native CSS custom properties (like
var(--bg-surface), var(--text-main), and var(--border-color)) inside component inline styles to guarantee full dark mode compatibility.