Claude Skill

compone

Builds Python components using the compone framework for type-safe HTML/XML/RSS generation. Use when working with compone, creating Python components, generating markup in Python, or building framework-agnostic component libraries.

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download kissgyorgy-coding-agents-skills_compone-ad8dfa8.zip · 13 KB
Part of kissgyorgy/coding-agents — 7 skills

Install

skills CLI npx skills add https://github.com/kissgyorgy/coding-agents/tree/master/skills/compone
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install kissgyorgy-coding-agents@llmmart
Git git clone https://github.com/kissgyorgy/coding-agents.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole kissgyorgy/coding-agents collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Compone - Python Component Framework

Helps developers create type-safe, reusable components using compone, a modern Python framework for generating markup (HTML, XML, RSS) with React-like patterns.

ALWAYS read core-concepts.md for basic usage.

When to Use Compone

  • Building framework-agnostic component libraries
  • Type-safe HTML generation in Python
  • Colocating markup with Python logic
  • Generating XML, RSS, or other markup formats
  • Creating reusable UI patterns across projects
  • Teams preferring Python over template languages

Best Practices

  1. Type all props: Use type hints for better IDE support and static type checking
  2. Single responsibility: Keep components focused on one concern
  3. Composition over complexity: Build complex UIs from simple components
  4. Descriptive names: Use clear component and prop names
  5. Default values: Provide sensible defaults for optional props
  6. Framework agnostic: Don't tie components to specific web frameworks

Official Documentation

Files (coding-agents)
  • core-concepts.md 7.3 KB
    # Core Concepts
    
    Basic features of compone, creating components, using attributes.
    
    ## Importing
    
    ```python
    # HTML components
    from compone import Component, html
    
    # XML components
    from compone import Component, xml
    ```
    
    ## Basic Component Syntax
    
    Components are created using the `@Component` decorator:
    
    ```python
    from compone import Component, html
    
    @Component
    def Button(text: str, variant: str = "primary", children=None):
        return html.Button(class_=f"btn btn-{variant}")[
            text,
            children,
        ]
    ```
    
    **Key points:**
    - Use `@Component` decorator on functions
    - Type hint all parameters (required for type safety)
    - `children` parameter receives nested content
    - Return markup using bracket notation for simple components
    - Use context manager syntax for complex components with inline code
    
    ## Nesting Components
    
    Components are called like functions and can be nested:
    
    ```python
    # Simple usage
    Button("Click me")
    
    # With children using bracket notation
    Button("Submit")["Save changes"]
    
    # Nested components
    html.Form[
        html.Label["Name:"],
        html.Input(type="text", name="username"),
        Button("Submit", variant="success"),
    ]
    ```
    
    ### Children Handling
    
    The `children` parameter captures nested content:
    
    ```python
    @Component
    def Card(title: str, children=None):
        return html.Div(class_="card")[
            html.H2[title],
            html.Div(class_="card-body")[children],
        ]
    
    Card("My Card")[
        html.P["First paragraph"],
        html.P["Second paragraph"],
    ]
    ```
    
    ### Bracket Notation
    
    You can nest elements with bracket notation
    
    ```python
    html.Div[
        html.H1["Title"],
        html.P["Paragraph text"],
    ]
    ```
    
    - `html.TagName[children]` creates elements, `children` is passed as children keyword argument
    - Multiple children separated by commas
    - Strings, other elements, and components can be nested
    - Use parentheses for attributes: `html.Div(class_="container")[...]`
    
    ### Context manager notation
    
    You can nest elements with context manager notation too:
    
    ```python
    from compone import Component, html
    
    @Component
    def ComplexComponent(text: str, variant: str = "primary", children=None):
        with html.Div(class_="container") as div:
            with html.Span(class_="italic") as span:
                span += html.Button(class_=f"btn btn-{variant}")[
                    text,
                    children,
                ]
        return div
    ```
    
    You can mix and match Context Manager Notation and Bracket Notation, use the inline append operator `+=`
    to append elements as the children of the context manager object.
    
    They render the same way, for example, this components render the same output as the `ComplexComponent`:
    
    ```python
    @Component
    def ComplexComponent(text: str, variant: str = "primary", children=None):
        return html.Div(class_="container")[
            html.Span(class_="italic")[
                html.Button(class_=f"btn btn-{variant}")[
                    text,
                    children,
                ]
            ]
        ]
    ```
    
    
    ## Element Attributes
    
    ### Basic Attributes
    
    Pass attributes as keyword arguments:
    
    ```python
    html.Div(id="container", class_="wrapper")
    html.A(href="/page", title="Link title")
    html.Img(src="image.jpg", alt="Description")
    ```
    
    ### Hyphenated Attributes
    
    Use underscores for hyphens in attribute names:
    
    ```python
    html.Div(data_id="123")          # becomes data-id
    html.Meta(http_equiv="refresh")  # becomes http-equiv
    html.Button(aria_label="Close")  # becomes aria-label
    ```
    
    ### Boolean Attributes
    
    Pass boolean values directly:
    
    ```python
    html.Input(type="checkbox", checked=True)
    html.Button(disabled=True)
    html.Script(async_=True, defer=True)
    ```
    
    Attributes with `False` value will not be rendered.
    
    ### Python keyword Attributes
    
    Python keywords require trailing underscore:
    
    ```python
    html.Label(for_="input-id")      # for is reserved
    html.Div(class_="my-class")      # class is reserved
    ```
    
    Attributes which are not valid Python argument names, can still be passed:
    ```python
    html.Label(**{"invalid:python*-variable": "value"})
    # <label invalid:python*-variable="value"></label>
    ```
    
    ### Default Values
    
    ```python
    @Component
    def Button(
        text: str,
        variant: str = "primary",
        size: str = "md",
        disabled: bool = False,
        children=None
    ):
        return html.Button(
            class_=f"btn btn-{variant} btn-{size}",
            disabled=disabled
        )[text, children]
    ```
    
    ### Required vs Optional Attributes
    
    ```python
    from typing import Optional
    
    @Component
    def Article(
        title: str,                    # Required
        content: str,                  # Required
        author: Optional[str] = None,  # Optional
        tags: list[str] = [],          # Optional with default
        children=None
    ):
        return html.Article[
            html.H1[title],
            html.P(class_="author")[f"By {author}"] if author else None,
            html.Div[content],
            html.Div(class_="tags")[
                [html.Span[tag] for tag in tags]
            ] if tags else None,
            children,
        ]
    ```
    
    
    ## Self-Closing Elements
    
    Elements that don't have closing tags use parentheses for attributes only:
    
    ```python
    html.Img(src="image.jpg", alt="Description")
    html.Input(type="text", name="username")
    html.Br()
    html.Hr()
    html.Meta(charset="utf-8")
    html.Link(rel="stylesheet", href="style.css")
    ```
    
    
    ## Type Safety
    
    Leverage Python type hints for IDE support.
    ALWAYS type hint ALL arguments:
    
    ```python
    from typing import Literal
    
    @Component
    def Alert(
        message: str,
        level: Literal["info", "warning", "error"],
        dismissible: bool = False,
        children=None
    ):
        return html.Div(
            class_=f"alert alert-{level}",
            role="alert"
        )[
            message,
            children,
            html.Button("×") if dismissible else None,
        ]
    
    # IDE will autocomplete and validate level parameter
    Alert("Something went wrong", level="error", dismissible=True)
    ```
    
    ## Conditional Rendering
    
    Use None with conditional expressions to ignore element rendering:
    
    ```python
    @Component
    def Message(text: str, show_icon: bool = True, children=None):
        return html.Div[
            html.I(class_="icon") if show_icon else None,
            html.Span[text],
            children,
        ]
    ```
    
    
    ## List Rendering
    
    Use Python list comprehensions to render repeating elements:
    
    ```python
    @Component
    def TodoList(items: list[str], children=None):
        return html.Ul[
            [html.Li[item] for item in items],
            children,
        ]
    
    # Usage
    TodoList(["Task 1", "Task 2", "Task 3"])
    ```
    
    ### Caching Static Components
    
    ```python
    from functools import lru_cache
    
    @lru_cache(maxsize=128)
    @Component
    def StaticHeader(site_name: str):
        return html.Header[
            html.H1[site_name],
            html.Nav[
                html.A(href="/")["Home"],
                html.A(href="/about")["About"],
            ],
        ]
    
    # Subsequent calls with same args use cached result
    header1 = StaticHeader("My Site")
    header2 = StaticHeader("My Site")  # Returns cached
    ```
    
    ### Prerendering Components
    
    When a component can be completely static, render them at import time
    and use contant variables:
    
    ```python
    # Compute expensive strings once
    FOOTER_HTML = str(html.Footer[
        html.P["© 2024 Company"],
        html.Nav[
            html.A(href="/terms")["Terms"],
            html.A(href="/privacy")["Privacy"],
        ],
    ])
    
    @Component
    def Page(title: str, children):
        return html.Html[
            html.Head[html.Title[title]],
            html.Body[
                children,
                FOOTER_HTML,  # Reuse precomputed string
            ],
        ]
    ```
    
  • examples.md 13.7 KB
    ## Component Libraries
    
    ### UI Component Library
    
    ```python
    # ui_library.py
    from compone import Component, html
    from typing import Literal, Optional
    
    @Component
    def Container(
        max_width: Literal["sm", "md", "lg", "xl"] = "lg",
        children=None
    ):
        widths = {"sm": "640px", "md": "768px", "lg": "1024px", "xl": "1280px"}
        return html.Div(
            class_="container",
            style=f"max-width: {widths[max_width]}; margin: 0 auto; padding: 0 1rem;"
        )[children]
    
    @Component
    def Button(
        text: str,
        variant: Literal["primary", "secondary", "danger"] = "primary",
        size: Literal["sm", "md", "lg"] = "md",
        disabled: bool = False,
        children=None
    ):
        return html.Button(
            class_=f"btn btn-{variant} btn-{size}",
            disabled=disabled
        )[text, children]
    
    @Component
    def Card(
        title: Optional[str] = None,
        footer: Optional[str] = None,
        children=None
    ):
        return html.Div(class_="card")[
            html.Div(class_="card-header")[html.H3[title]] if title else None,
            html.Div(class_="card-body")[children],
            html.Div(class_="card-footer")[footer] if footer else None,
        ]
    
    @Component
    def Grid(
        cols: int = 2,
        gap: int = 4,
        children=None
    ):
        return html.Div(
            class_="grid",
            style=f"display: grid; grid-template-columns: repeat({cols}, 1fr); gap: {gap}rem;"
        )[children]
    
    @Component
    def Alert(
        message: str,
        level: Literal["info", "warning", "error", "success"] = "info",
        dismissible: bool = False,
        children=None
    ):
        icons = {
            "info": "ℹ",
            "warning": "⚠",
            "error": "✖",
            "success": "✓",
        }
        return html.Div(
            class_=f"alert alert-{level}",
            role="alert"
        )[
            html.Span(class_="alert-icon")[icons[level]],
            html.Span[message, children],
            html.Button(
                class_="alert-close",
                type="button",
                aria_label="Close"
            )["×"] if dismissible else None,
        ]
    
    @Component
    def Badge(
        text: str,
        variant: Literal["primary", "secondary", "success", "danger"] = "primary",
    ):
        return html.Span(class_=f"badge badge-{variant}")[text]
    
    @Component
    def List(
        items: list[str],
        ordered: bool = False,
        children=None
    ):
        ListTag = html.Ol if ordered else html.Ul
        return ListTag[
            [html.Li[item] for item in items],
            children,
        ]
    
    # Usage example
    if __name__ == "__main__":
        page = Container(max_width="lg")[
            html.H1["Component Library Demo"],
    
            Alert("This is an info alert", level="info", dismissible=True),
    
            Grid(cols=3, gap=2)[
                Card(title="Card 1", footer="Footer 1")[
                    html.P["Card content here"],
                    Button("Click me", variant="primary"),
                ],
                Card(title="Card 2", footer="Footer 2")[
                    html.P["More content"],
                    Button("Action", variant="secondary"),
                ],
                Card(title="Card 3")[
                    html.P["Another card"],
                    Badge("New", variant="success"),
                ],
            ],
    
            List(["Item 1", "Item 2", "Item 3"], ordered=True),
        ]
    
        print(str(page))
    ```
    
    ### Form Component Library
    
    ```python
    # forms.py
    from compone import Component, html
    from typing import Optional, Literal
    
    @Component
    def FormGroup(
        label: str,
        name: str,
        help_text: Optional[str] = None,
        error: Optional[str] = None,
        required: bool = False,
        children=None
    ):
        return html.Div(class_="form-group")[
            html.Label(for_=name, class_="form-label")[
                label,
                html.Span(class_="required")["*"] if required else None,
            ],
            children,
            html.Small(class_="form-help")[help_text] if help_text else None,
            html.Div(class_="form-error")[error] if error else None,
        ]
    
    @Component
    def TextInput(
        name: str,
        type: Literal["text", "email", "password", "tel", "url"] = "text",
        value: str = "",
        placeholder: str = "",
        required: bool = False,
        disabled: bool = False,
    ):
        return html.Input(
            type=type,
            id=name,
            name=name,
            value=value,
            placeholder=placeholder,
            required=required,
            disabled=disabled,
            class_="form-input"
        )
    
    @Component
    def TextArea(
        name: str,
        value: str = "",
        rows: int = 4,
        placeholder: str = "",
        required: bool = False,
    ):
        return html.Textarea(
            id=name,
            name=name,
            rows=rows,
            placeholder=placeholder,
            required=required,
            class_="form-textarea"
        )[value]
    
    @Component
    def Select(
        name: str,
        options: list[tuple[str, str]],  # [(value, label), ...]
        selected: str = "",
        required: bool = False,
    ):
        return html.Select(
            id=name,
            name=name,
            required=required,
            class_="form-select"
        )[
            [html.Option(
                value=value,
                selected=(value == selected)
            )[label] for value, label in options]
        ]
    
    @Component
    def Checkbox(
        name: str,
        label: str,
        checked: bool = False,
        value: str = "1",
    ):
        return html.Div(class_="form-checkbox")[
            html.Input(
                type="checkbox",
                id=name,
                name=name,
                value=value,
                checked=checked
            ),
            html.Label(for_=name)[label],
        ]
    
    @Component
    def RadioGroup(
        name: str,
        options: list[tuple[str, str]],  # [(value, label), ...]
        selected: str = "",
    ):
        return html.Div(class_="form-radio-group")[
            [html.Div(class_="form-radio")[
                html.Input(
                    type="radio",
                    id=f"{name}_{value}",
                    name=name,
                    value=value,
                    checked=(value == selected)
                ),
                html.Label(for_=f"{name}_{value}")[label],
            ] for value, label in options]
        ]
    
    # Usage
    registration_form = html.Form(method="post", action="/register")[
        FormGroup(
            label="Email",
            name="email",
            required=True,
            help_text="We'll never share your email"
        )[
            TextInput(name="email", type="email", required=True)
        ],
    
        FormGroup(
            label="Password",
            name="password",
            required=True,
            help_text="At least 8 characters"
        )[
            TextInput(name="password", type="password", required=True)
        ],
    
        FormGroup(
            label="Country",
            name="country",
            required=True
        )[
            Select(
                name="country",
                options=[
                    ("us", "United States"),
                    ("uk", "United Kingdom"),
                    ("ca", "Canada"),
                ],
                required=True
            )
        ],
    
        FormGroup(
            label="Bio",
            name="bio"
        )[
            TextArea(name="bio", placeholder="Tell us about yourself")
        ],
    
        Checkbox(name="newsletter", label="Subscribe to newsletter"),
    
        html.Button(type="submit", class_="btn-primary")["Register"],
    ]
    ```
    
    ## Type-Safe Development
    
    ### Type-Safe Component Props
    
    ```python
    from compone import Component, html
    from typing import Literal, TypedDict, Optional
    from datetime import datetime
    
    class User(TypedDict):
        id: int
        name: str
        email: str
        avatar_url: Optional[str]
        role: Literal["admin", "user", "guest"]
    
    class Post(TypedDict):
        id: int
        title: str
        content: str
        author: User
        created_at: datetime
        tags: list[str]
    
    @Component
    def UserAvatar(
        user: User,
        size: Literal["sm", "md", "lg"] = "md",
    ):
        sizes = {"sm": "32", "md": "48", "lg": "64"}
        return html.Div(class_=f"avatar avatar-{size}")[
            html.Img(
                src=user["avatar_url"] or "/default-avatar.png",
                alt=user["name"],
                width=sizes[size],
                height=sizes[size]
            ) if user.get("avatar_url") else html.Div(class_="avatar-placeholder")[
                user["name"][0].upper()
            ]
        ]
    
    @Component
    def UserBadge(user: User):
        badge_colors = {
            "admin": "red",
            "user": "blue",
            "guest": "gray",
        }
        return html.Span(
            class_=f"badge badge-{badge_colors[user['role']]}"
        )[user["role"].title()]
    
    @Component
    def PostCard(post: Post, show_author: bool = True):
        return html.Article(class_="post-card")[
            html.Header[
                html.H2[html.A(href=f"/posts/{post['id']}")[post["title"]]],
                html.Div(class_="post-meta")[
                    UserAvatar(post["author"], size="sm") if show_author else None,
                    html.Span[post["author"]["name"]] if show_author else None,
                    html.Time(datetime=post["created_at"].isoformat())[
                        post["created_at"].strftime("%B %d, %Y")
                    ],
                ],
            ],
            html.Div(class_="post-content")[post["content"][:200] + "..."],
            html.Footer[
                html.Div(class_="post-tags")[
                    [html.Span(class_="tag")[f"#{tag}"] for tag in post["tags"]]
                ],
                html.A(href=f"/posts/{post['id']}")["Read more →"],
            ],
        ]
    
    # Usage with type checking
    user: User = {
        "id": 1,
        "name": "John Doe",
        "email": "john@example.com",
        "avatar_url": "https://example.com/avatar.jpg",
        "role": "admin",  # IDE will autocomplete and validate
    }
    
    post: Post = {
        "id": 1,
        "title": "My First Post",
        "content": "This is the content of my first post...",
        "author": user,
        "created_at": datetime.now(),
        "tags": ["python", "web", "compone"],
    }
    
    # Type errors caught by IDE:
    # PostCard(post, show_author="yes")  # Error: bool expected, got str
    # user["role"] = "superuser"  # Error: Literal type violation
    ```
    
    ### Generic Components with TypeVars
    
    ```python
    from typing import TypeVar, Generic, Callable
    from compone import Component, html
    
    T = TypeVar('T')
    
    @Component
    def DataList(
        items: list[T],
        render_item: Callable[[T], any],
        empty_message: str = "No items to display",
        children=None
    ):
        if not items:
            return html.P(class_="empty-state")[empty_message]
    
        return html.Div(class_="data-list")[
            [html.Div(class_="data-list-item")[render_item(item)] for item in items],
            children,
        ]
    
    # Usage with type inference
    users = [
        {"name": "Alice", "email": "alice@example.com"},
        {"name": "Bob", "email": "bob@example.com"},
    ]
    
    user_list = DataList(
        items=users,
        render_item=lambda u: html.Div[
            html.Strong[u["name"]],
            html.Span[u["email"]],
        ],
        empty_message="No users found"
    )
    ```
    
    
    ## Real-World Examples
    
    ### Complete Blog with Admin Panel
    
    ```python
    from flask import Flask, request, redirect, session
    from compone import Component, html
    from typing import Optional
    
    app = Flask(__name__)
    app.secret_key = "dev"
    
    # Mock database
    posts_db = []
    users_db = {"admin": "password"}
    
    @Component
    def AdminLayout(title: str, children):
        return html.Html[
            html.Head[
                html.Meta(charset="utf-8"),
                html.Title[f"{title} - Admin"],
                html.Link(rel="stylesheet", href="/static/admin.css"),
            ],
            html.Body[
                html.Header[
                    html.H1["Blog Admin"],
                    html.Nav[
                        html.A(href="/admin")["Dashboard"],
                        html.A(href="/admin/posts")["Posts"],
                        html.A(href="/logout")["Logout"],
                    ],
                ],
                html.Main[children],
            ],
        ]
    
    @Component
    def PostEditor(
        post_id: Optional[int] = None,
        title: str = "",
        content: str = "",
    ):
        action = f"/admin/posts/{post_id}/edit" if post_id else "/admin/posts/create"
        return html.Form(action=action, method="post")[
            html.Div[
                html.Label(for_="title")["Title"],
                html.Input(type="text", id="title", name="title", value=title, required=True),
            ],
            html.Div[
                html.Label(for_="content")["Content"],
                html.Textarea(id="content", name="content", rows=10, required=True)[content],
            ],
            html.Button(type="submit")["Save Post"],
        ]
    
    @app.route("/admin/posts")
    def admin_posts():
        if "user" not in session:
            return redirect("/login")
    
        return str(AdminLayout("Posts")[
            html.H2["All Posts"],
            html.A(href="/admin/posts/new", class_="btn")["New Post"],
            html.Table[
                html.Thead[
                    html.Tr[
                        html.Th["Title"],
                        html.Th["Created"],
                        html.Th["Actions"],
                    ]
                ],
                html.Tbody[
                    [html.Tr[
                        html.Td[post["title"]],
                        html.Td[post["created_at"]],
                        html.Td[
                            html.A(href=f"/admin/posts/{i}/edit")["Edit"],
                            html.Form(
                                action=f"/admin/posts/{i}/delete",
                                method="post",
                                style="display:inline"
                            )[
                                html.Button(type="submit")["Delete"]
                            ],
                        ],
                    ] for i, post in enumerate(posts_db)]
                ] if posts_db else html.Tbody[
                    html.Tr[html.Td(colspan="3")["No posts yet"]]
                ]
            ],
        ])
    
    @app.route("/admin/posts/new")
    def new_post():
        if "user" not in session:
            return redirect("/login")
        return str(AdminLayout("New Post")[
            html.H2["Create New Post"],
            PostEditor(),
        ])
    
    @app.route("/admin/posts/create", methods=["POST"])
    def create_post():
        if "user" not in session:
            return redirect("/login")
    
        posts_db.append({
            "title": request.form["title"],
            "content": request.form["content"],
            "created_at": datetime.now().strftime("%Y-%m-%d %H:%M"),
        })
        return redirect("/admin/posts")
    ```
    
    This comprehensive examples file covers all the requested use cases with practical, working code examples.
    
  • frameworks.md 6.8 KB
    # Web Framework Integration
    
    Compone components return strings that work with any Python web framework:
    
    ```python
    # Flask
    @app.route("/")
    def index():
        return str(HomePage()["Welcome"])
    
    # FastAPI
    @app.get("/")
    def index():
        return HTMLResponse(HomePage()["Welcome"])
    
    # Django
    def index(request):
        return HttpResponse(HomePage()["Welcome"])
    ```
    
    
    ## Flask Blog Application
    
    ```python
    from flask import Flask, request
    from compone import Component, html
    
    app = Flask(__name__)
    
    @Component
    def Layout(title: str, children):
        return html.Html[
            html.Head[
                html.Meta(charset="utf-8"),
                html.Title[title],
                html.Link(rel="stylesheet", href="/static/style.css"),
            ],
            html.Body[
                html.Header[
                    html.H1["My Blog"],
                    html.Nav[
                        html.A(href="/")["Home"],
                        html.A(href="/about")["About"],
                    ],
                ],
                html.Main[children],
                html.Footer[
                    html.P["© 2024 My Blog"],
                ],
            ],
        ]
    
    @Component
    def PostCard(title: str, excerpt: str, date: str, url: str):
        return html.Article(class_="post-card")[
            html.H2[html.A(href=url)[title]],
            html.Time(datetime=date)[date],
            html.P[excerpt],
            html.A(href=url, class_="read-more")["Read more →"],
        ]
    
    @Component
    def PostList(posts: list, children=None):
        return html.Div(class_="post-list")[
            [PostCard(
                title=post["title"],
                excerpt=post["excerpt"],
                date=post["date"],
                url=f"/post/{post['id']}"
            ) for post in posts],
            children,
        ]
    
    @app.route("/")
    def index():
        posts = [
            {"id": 1, "title": "First Post", "excerpt": "This is my first post...", "date": "2024-01-01"},
            {"id": 2, "title": "Second Post", "excerpt": "Another great post...", "date": "2024-01-05"},
        ]
        return str(Layout("Home")[PostList(posts)])
    
    @app.route("/post/<int:post_id>")
    def post_detail(post_id):
        post = {
            "title": f"Post {post_id}",
            "content": "Full post content here...",
            "date": "2024-01-01",
        }
        return str(Layout(post["title"])[
            html.Article[
                html.H1[post["title"]],
                html.Time(datetime=post["date"])[post["date"]],
                html.Div(class_="content")[post["content"]],
            ]
        ])
    
    if __name__ == "__main__":
        app.run(debug=True)
    ```
    
    
    ## FastAPI App with HTML Views
    
    ```python
    from fastapi import FastAPI, Form, Request
    from fastapi.responses import HTMLResponse, RedirectResponse
    from compone import Component, html
    from typing import Optional
    
    app = FastAPI()
    
    @Component
    def Page(title: str, children):
        return html.Html[
            html.Head[
                html.Meta(charset="utf-8"),
                html.Meta(name="viewport", content="width=device-width, initial-scale=1"),
                html.Title[title],
                html.Link(rel="stylesheet", href="https://cdn.simplecss.org/simple.min.css"),
            ],
            html.Body[children],
        ]
    
    @Component
    def Form(action: str, method: str = "post", children=None):
        return html.Form(action=action, method=method)[children]
    
    @Component
    def TextField(
        name: str,
        label: str,
        type: str = "text",
        required: bool = False,
        value: str = "",
    ):
        return html.Div[
            html.Label(for_=name)[label],
            html.Input(
                type=type,
                id=name,
                name=name,
                value=value,
                required=required,
            ),
        ]
    
    @Component
    def Button(text: str, type: str = "submit", children=None):
        return html.Button(type=type)[text, children]
    
    # In-memory database
    tasks = []
    
    @app.get("/", response_class=HTMLResponse)
    async def task_list():
        return str(Page("Todo List")[
            html.H1["My Tasks"],
            html.Ul[
                [html.Li[
                    task["title"],
                    html.Form(action=f"/tasks/{i}/delete", method="post", style="display:inline")[
                        Button("Delete", type="submit")
                    ]
                ] for i, task in enumerate(tasks)]
            ] if tasks else html.P["No tasks yet."],
            html.H2["Add Task"],
            Form(action="/tasks/create")[
                TextField("title", "Task", required=True),
                Button("Add Task"),
            ],
        ])
    
    @app.post("/tasks/create", response_class=RedirectResponse)
    async def create_task(title: str = Form(...)):
        tasks.append({"title": title, "completed": False})
        return RedirectResponse(url="/", status_code=303)
    
    @app.post("/tasks/{task_id}/delete", response_class=RedirectResponse)
    async def delete_task(task_id: int):
        if 0 <= task_id < len(tasks):
            tasks.pop(task_id)
        return RedirectResponse(url="/", status_code=303)
    ```
    
    
    ## Django View with Components
    
    ```python
    # components.py
    from compone import Component, html
    from typing import Optional
    
    @Component
    def BaseLayout(title: str, children):
        return html.Html[
            html.Head[
                html.Meta(charset="utf-8"),
                html.Title[f"{title} - My Django Site"],
                html.Link(rel="stylesheet", href="/static/css/style.css"),
            ],
            html.Body[
                html.Header[
                    html.Nav[
                        html.A(href="/")["Home"],
                        html.A(href="/products/")["Products"],
                        html.A(href="/contact/")["Contact"],
                    ],
                ],
                html.Main[children],
            ],
        ]
    
    @Component
    def ProductCard(name: str, price: float, image_url: str, product_id: int):
        return html.Div(class_="product-card")[
            html.Img(src=image_url, alt=name),
            html.H3[name],
            html.P(class_="price")[f"${price:.2f}"],
            html.A(href=f"/products/{product_id}/", class_="btn")["View Details"],
        ]
    
    # views.py
    from django.http import HttpResponse
    from .components import BaseLayout, ProductCard
    from .models import Product
    
    def product_list(request):
        products = Product.objects.all()
    
        content = BaseLayout("Products")[
            html.H1["Our Products"],
            html.Div(class_="product-grid")[
                [ProductCard(
                    name=p.name,
                    price=p.price,
                    image_url=p.image.url,
                    product_id=p.id
                ) for p in products]
            ],
        ]
    
        return HttpResponse(str(content))
    
    def product_detail(request, product_id):
        product = Product.objects.get(id=product_id)
    
        content = BaseLayout(product.name)[
            html.Article[
                html.H1[product.name],
                html.Img(src=product.image.url, alt=product.name),
                html.P(class_="price")[f"${product.price:.2f}"],
                html.Div(class_="description")[product.description],
                html.Form(action=f"/cart/add/{product.id}/", method="post")[
                    html.Button(type="submit")["Add to Cart"],
                ],
            ],
        ]
    
        return HttpResponse(str(content))
    ```
    
  • html.md 5.6 KB
    # HTML Module
    
    The `html` module provides all standard HTML5 elements.
    
    ## Structure Elements
    
    ```python
    html.Html[...]           # <html>
    html.Head[...]           # <head>
    html.Body[...]           # <body>
    html.Div[...]            # <div>
    html.Span[...]           # <span>
    html.Main[...]           # <main>
    html.Header[...]         # <header>
    html.Footer[...]         # <footer>
    html.Nav[...]            # <nav>
    html.Section[...]        # <section>
    html.Article[...]        # <article>
    html.Aside[...]          # <aside>
    ```
    
    ## Text Elements
    
    ```python
    html.H1[...]             # <h1>
    html.H2[...]             # <h2>
    html.H3[...]             # <h3>
    html.H4[...]             # <h4>
    html.H5[...]             # <h5>
    html.H6[...]             # <h6>
    html.P[...]              # <p>
    html.A[...]              # <a>
    html.Strong[...]         # <strong>
    html.Em[...]             # <em>
    html.Code[...]           # <code>
    html.Pre[...]            # <pre>
    html.Blockquote[...]     # <blockquote>
    html.Small[...]          # <small>
    html.Mark[...]           # <mark>
    html.Del[...]            # <del>
    html.Ins[...]            # <ins>
    html.Sub[...]            # <sub>
    html.Sup[...]            # <sup>
    ```
    
    ## List Elements
    
    ```python
    html.Ul[...]             # <ul>
    html.Ol[...]             # <ol>
    html.Li[...]             # <li>
    html.Dl[...]             # <dl>
    html.Dt[...]             # <dt>
    html.Dd[...]             # <dd>
    ```
    
    ## Table Elements
    
    ```python
    html.Table[...]          # <table>
    html.Thead[...]          # <thead>
    html.Tbody[...]          # <tbody>
    html.Tfoot[...]          # <tfoot>
    html.Tr[...]             # <tr>
    html.Th[...]             # <th>
    html.Td[...]             # <td>
    html.Caption[...]        # <caption>
    html.Colgroup[...]       # <colgroup>
    html.Col[...]            # <col>
    ```
    
    ## Form Elements
    
    ```python
    html.Form[...]           # <form>
    html.Input(...)          # <input> (self-closing)
    html.Textarea[...]       # <textarea>
    html.Button[...]         # <button>
    html.Select[...]         # <select>
    html.Option[...]         # <option>
    html.Label[...]          # <label>
    html.Fieldset[...]       # <fieldset>
    html.Legend[...]         # <legend>
    html.Datalist[...]       # <datalist>
    html.Output[...]         # <output>
    html.Progress(...)       # <progress>
    html.Meter(...)          # <meter>
    ```
    
    ## Media Elements
    
    ```python
    html.Img(...)            # <img> (self-closing)
    html.Video[...]          # <video>
    html.Audio[...]          # <audio>
    html.Source(...)         # <source> (self-closing)
    html.Track(...)          # <track> (self-closing)
    html.Picture[...]        # <picture>
    html.Svg[...]            # <svg>
    html.Canvas[...]         # <canvas>
    ```
    
    ## Interactive Elements
    
    ```python
    html.Details[...]        # <details>
    html.Summary[...]        # <summary>
    html.Dialog[...]         # <dialog>
    ```
    
    ## Metadata Elements
    
    ```python
    html.Title[...]          # <title>
    html.Meta(...)           # <meta> (self-closing)
    html.Link(...)           # <link> (self-closing)
    html.Style[...]          # <style>
    html.Script[...]         # <script>
    html.Noscript[...]       # <noscript>
    html.Base(...)           # <base> (self-closing)
    ```
    
    ## Other Elements
    
    ```python
    html.Br(...)             # <br> (self-closing)
    html.Hr(...)             # <hr> (self-closing)
    html.Iframe[...]         # <iframe>
    html.Embed(...)          # <embed> (self-closing)
    html.Object[...]         # <object>
    html.Param(...)          # <param> (self-closing)
    html.Time[...]           # <time>
    html.Data[...]           # <data>
    html.Abbr[...]           # <abbr>
    html.Address[...]        # <address>
    html.Cite[...]           # <cite>
    html.Kbd[...]            # <kbd>
    html.Samp[...]           # <samp>
    html.Var[...]            # <var>
    html.Wbr(...)            # <wbr> (self-closing)
    ```
    
    ## Component Composition
    
    Build complex components from simpler ones:
    
    ```python
    @Component
    def Button(text: str, variant: str = "primary", children=None):
        return html.Button(class_=f"btn btn-{variant}")[text, children]
    
    @Component
    def IconButton(icon: str, text: str, children=None):
        return Button(text)[
            html.I(class_=f"icon-{icon}"),
            children,
        ]
    
    @Component
    def Modal(title: str, show_close: bool = True, children=None):
        return html.Div(class_="modal")[
            html.Div(class_="modal-header")[
                html.H2[title],
                IconButton("close", "Close") if show_close else None,
            ],
            html.Div(class_="modal-body")[children],
        ]
    ```
    
    ## Modifying Element Attributes
    
    Elements have `.append()` and `.replace()` methods to derive new elements with modified attributes.
    Access current attributes with `.props`.
    
    ### `.append()` — Add to existing attributes
    
    Appends values to existing attributes (space-separated for `class`):
    
    ```python
    el = html.Input(type="text", class_="base")
    el2 = el.append(class_="extra")
    str(el2)  # <input type="text" class="base extra" />
    ```
    
    ### `.replace()` — Override attributes
    
    Replaces attribute values entirely:
    
    ```python
    el = html.Div(class_="old", id="box")
    el2 = el.replace(class_="new")
    str(el2)  # <div class="new" id="box"></div>
    ```
    
    ### `.props` — Read current attributes
    
    ```python
    el = html.Div(class_="card", id="main")
    el.props  # {'class_': ['card'], 'id': 'main'}
    ```
    
    Note: `class_` values are stored as lists (since multiple classes are common).
    
    These methods return **new elements** — the original is not mutated.
    
    ## Escaping and Raw HTML
    
    Compone automatically escapes strings for security. For raw HTML:
    
    ```python
    from compone import safe
    
    @Component
    def RawContent(html_string: str, children=None):
        # WARNING: Only use with trusted content
        return html.Div[safe(html_string), children]
    ```
    
  • other-formats.md 6.1 KB
    # Non-HTML Formats
    
    Compone supports XML, RSS, and custom markup:
    
    ```python
    from compone import xml
    
    @Component
    def RSSItem(title: str, link: str, description: str):
        return xml.Item[
            xml.Title[title],
            xml.Link[link],
            xml.Description[description],
        ]
    
    # Generate RSS feed
    feed = xml.Rss(version="2.0")[
        xml.Channel[
            xml.Title["My Blog"],
            RSSItem("Post 1", "https://...", "Description"),
            RSSItem("Post 2", "https://...", "Description"),
        ]
    ]
    ```
    
    ## XML Module
    
    The `xml` module provides XML element creation.
    
    ### Generic XML Elements
    
    ```python
    from compone import xml
    
    # Create any XML element by attribute access
    xml.Root[...]
    xml.Item[...]
    xml.CustomTag[...]
    ```
    
    ### Common XML Formats
    
    #### RSS Feed Example
    
    ```python
    xml.Rss(version="2.0")[
        xml.Channel[
            xml.Title["Feed Title"],
            xml.Link["https://example.com"],
            xml.Description["Feed description"],
            xml.Item[
                xml.Title["Item title"],
                xml.Link["https://example.com/item"],
                xml.Description["Item description"],
                xml.PubDate["Mon, 01 Jan 2024 00:00:00 GMT"],
            ],
        ]
    ]
    ```
    
    #### Atom Feed Example
    
    ```python
    xml.Feed(xmlns="http://www.w3.org/2005/Atom")[
        xml.Title["Feed Title"],
        xml.Link(href="https://example.com"),
        xml.Updated["2024-01-01T00:00:00Z"],
        xml.Entry[
            xml.Title["Entry title"],
            xml.Link(href="https://example.com/entry"),
            xml.Updated["2024-01-01T00:00:00Z"],
            xml.Summary["Entry summary"],
        ],
    ]
    ```
    
    #### Sitemap Example
    
    ```python
    xml.Urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")[
        xml.Url[
            xml.Loc["https://example.com/page1"],
            xml.Lastmod["2024-01-01"],
            xml.Changefreq["weekly"],
            xml.Priority["0.8"],
        ],
    ]
    ```
    
    ## RSS Feed Generator
    
    ```python
    from compone import Component, xml
    from datetime import datetime
    from typing import TypedDict
    
    class RSSItem(TypedDict):
        title: str
        link: str
        description: str
        pub_date: datetime
        author: str
        guid: str
    
    @Component
    def RSS_Item(item: RSSItem):
        return xml.Item[
            xml.Title[item["title"]],
            xml.Link[item["link"]],
            xml.Description[item["description"]],
            xml.PubDate[item["pub_date"].strftime("%a, %d %b %Y %H:%M:%S %z")],
            xml.Author[item["author"]],
            xml.Guid(isPermaLink="true")[item["guid"]],
        ]
    
    @Component
    def RSS_Feed(
        title: str,
        link: str,
        description: str,
        items: list[RSSItem],
    ):
        return xml.Rss(version="2.0", xmlns_atom="http://www.w3.org/2005/Atom")[
            xml.Channel[
                xml.Title[title],
                xml.Link[link],
                xml.Description[description],
                xml.Language["en-us"],
                xml.LastBuildDate[datetime.now().strftime("%a, %d %b %Y %H:%M:%S %z")],
                xml.Atom_link(
                    href=f"{link}/rss.xml",
                    rel="self",
                    type="application/rss+xml"
                ),
                [RSS_Item(item) for item in items],
            ]
        ]
    
    # Usage
    blog_items = [
        {
            "title": "First Blog Post",
            "link": "https://example.com/posts/1",
            "description": "This is my first blog post about Python",
            "pub_date": datetime(2024, 1, 1, 12, 0, 0),
            "author": "john@example.com (John Doe)",
            "guid": "https://example.com/posts/1",
        },
        {
            "title": "Second Blog Post",
            "link": "https://example.com/posts/2",
            "description": "Another great post about web development",
            "pub_date": datetime(2024, 1, 5, 14, 30, 0),
            "author": "john@example.com (John Doe)",
            "guid": "https://example.com/posts/2",
        },
    ]
    
    feed = RSS_Feed(
        title="My Blog",
        link="https://example.com",
        description="A blog about Python and web development",
        items=blog_items
    )
    
    print('<?xml version="1.0" encoding="UTF-8"?>')
    print(str(feed))
    ```
    
    ## Sitemap Generator
    
    ```python
    from compone import Component, xml
    from datetime import datetime
    from typing import Literal
    
    ChangeFreq = Literal["always", "hourly", "daily", "weekly", "monthly", "yearly", "never"]
    
    @Component
    def URL(
        loc: str,
        lastmod: datetime,
        changefreq: ChangeFreq = "weekly",
        priority: float = 0.5,
    ):
        return xml.Url[
            xml.Loc[loc],
            xml.Lastmod[lastmod.strftime("%Y-%m-%d")],
            xml.Changefreq[changefreq],
            xml.Priority[f"{priority:.1f}"],
        ]
    
    @Component
    def Sitemap(urls: list[dict]):
        return xml.Urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")[
            [URL(
                loc=url["loc"],
                lastmod=url["lastmod"],
                changefreq=url.get("changefreq", "weekly"),
                priority=url.get("priority", 0.5),
            ) for url in urls]
        ]
    
    # Usage
    pages = [
        {
            "loc": "https://example.com/",
            "lastmod": datetime(2024, 1, 1),
            "changefreq": "daily",
            "priority": 1.0,
        },
        {
            "loc": "https://example.com/about",
            "lastmod": datetime(2024, 1, 1),
            "changefreq": "monthly",
            "priority": 0.8,
        },
        {
            "loc": "https://example.com/blog",
            "lastmod": datetime(2024, 1, 10),
            "changefreq": "weekly",
            "priority": 0.9,
        },
    ]
    
    sitemap = Sitemap(pages)
    print('<?xml version="1.0" encoding="UTF-8"?>')
    print(str(sitemap))
    ```
    
    ## SVG Generation
    
    ```python
    from compone import Component
    from compone import xml  # SVG uses xml module
    
    @Component
    def Circle(cx: int, cy: int, r: int, fill: str = "black"):
        return xml.Circle(cx=str(cx), cy=str(cy), r=str(r), fill=fill)
    
    @Component
    def Rect(x: int, y: int, width: int, height: int, fill: str = "black"):
        return xml.Rect(
            x=str(x),
            y=str(y),
            width=str(width),
            height=str(height),
            fill=fill
        )
    
    @Component
    def SVG(width: int, height: int, children):
        return xml.Svg(
            width=str(width),
            height=str(height),
            xmlns="http://www.w3.org/2000/svg"
        )[children]
    
    # Create a simple graphic
    graphic = SVG(200, 200)[
        Rect(0, 0, 200, 200, fill="#f0f0f0"),
        Circle(100, 100, 50, fill="#ff6b6b"),
        Circle(70, 80, 10, fill="white"),
        Circle(130, 80, 10, fill="white"),
    ]
    
    print(str(graphic))
    ```
    
  • SKILL.md 1.8 KB
    ---
    name: compone
    description: Builds Python components using the compone framework for type-safe HTML/XML/RSS generation. Use when working with compone, creating Python components, generating markup in Python, or building framework-agnostic component libraries.
    allowed-tools: Read, Write, Edit, Grep, Glob, Bash, WebFetch
    ---
    
    # Compone - Python Component Framework
    
    Helps developers create type-safe, reusable components using compone, a modern
    Python framework for generating markup (HTML, XML, RSS) with React-like patterns.
    
    ALWAYS read `core-concepts.md` for basic usage.
    
    - For integration with web frameworks, read [`frameworks.md`](frameworks.md).
    - For HTML generation and patterns, read [`html.md`](html.md)
    - For other formats like XML, RSS, SVG and others, read [`other-formats.md`](other-formats.md)
    - For more examples when writing complex components, read [`other-formats.md`](examples.md)
    - When writing tests for Components, read [`testing.md`](testing.md)
    
    ## When to Use Compone
    
    - Building framework-agnostic component libraries
    - Type-safe HTML generation in Python
    - Colocating markup with Python logic
    - Generating XML, RSS, or other markup formats
    - Creating reusable UI patterns across projects
    - Teams preferring Python over template languages
    
    
    ## Best Practices
    
    1. **Type all props**: Use type hints for better IDE support and static type checking
    2. **Single responsibility**: Keep components focused on one concern
    3. **Composition over complexity**: Build complex UIs from simple components
    4. **Descriptive names**: Use clear component and prop names
    5. **Default values**: Provide sensible defaults for optional props
    6. **Framework agnostic**: Don't tie components to specific web frameworks
    
    
    ## Official Documentation
    
    - Website: https://compone.kissgyorgy.me/
    - GitHub: https://github.com/kissgyorgy/compone
    - PyPI: https://pypi.org/project/compone/
    
  • testing.md 817 B
    # Testing compone Compoents
    
    Always assert on the full output when testing a Component.
    
    ```python
    import pytest
    from compone import Component, html
    
    @Component
    def Greeting(name: str, formal: bool = False):
        greeting = f"Hello, {name}" if not formal else f"Greetings, {name}"
        return html.Div[html.H1[greeting]]
    
    def test_greeting_informal():
        result = str(Greeting("Alice"))
        assert result == "<div><h1>Hello, Alice</h1></div>"
    
    def test_greeting_formal():
        result = str(Greeting("Bob", formal=True))
        assert result == "<div><h1>Greetings, Bob</h1></div>"
    
    ```
    
    
    ### Attribute Validation Testing
    
    ```python
    def test_progress_bar_validation():
        with pytest.raises(ValueError):
            ProgressBar(value=150, max_value=100)
    
        with pytest.raises(ValueError):
            ProgressBar(value=-10)
    ```
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related