Skip to content

Composition Patterns

Building complex layouts from simple components.

Container Composition

Basic Card Layout

from design_system import Card, CardHeader, Label, Button

card = Card()
card.add_widget(CardHeader(title="Section Title"))
card.add_widget(Label("Content goes here"))
card.add_widget(Button("Action", variant="primary"))

Panel with Header

from design_system import Panel, PanelHeader, FileList

panel = Panel()
panel.add_widget(PanelHeader(title="Files"))
panel.add_widget(FileList())

Hierarchical Data

Tree Structures

from design_system import CodeTree, CodeItem

tree = CodeTree()
tree.set_items([
    CodeItem("1", "Parent", "#FFC107", count=10, children=[
        CodeItem("1.1", "Child A", "#FFD54F", count=5),
        CodeItem("1.2", "Child B", "#FFE082", count=5),
    ])
])

Nested Layouts

from PySide6.QtWidgets import QHBoxLayout, QVBoxLayout
from design_system import Panel, Card, Label

# Main horizontal layout
main_layout = QHBoxLayout()

# Left sidebar
sidebar = Panel()
sidebar.add_widget(Label("Navigation"))
main_layout.addWidget(sidebar, stretch=1)

# Right content area
content = QVBoxLayout()

# Top card
top_card = Card()
top_card.add_widget(Label("Top Section"))
content.addWidget(top_card)

# Bottom card
bottom_card = Card()
bottom_card.add_widget(Label("Bottom Section"))
content.addWidget(bottom_card)

main_layout.addLayout(content, stretch=3)

Reusable Components

Create Compound Components

from design_system import (
    Panel, PanelHeader, SearchBox, FileList, EmptyState
)

class FileBrowser(Panel):
    """Reusable file browser component."""

    def __init__(self, title="Files"):
        super().__init__()

        # Header
        self.add_widget(PanelHeader(title=title))

        # Search
        self.search = SearchBox(placeholder="Search...")
        self.search.text_changed.connect(self._filter)
        self.add_widget(self.search)

        # File list
        self.file_list = FileList()
        self.add_widget(self.file_list)

        # Empty state
        self.empty = EmptyState(
            icon="mdi6.file-outline",
            title="No files",
            description="No files match your search"
        )
        self.empty.hide()
        self.add_widget(self.empty)

        self._all_files = []

    def set_files(self, files):
        self._all_files = files
        self._render_files(files)

    def _filter(self, query):
        filtered = [f for f in self._all_files
                    if query.lower() in f["name"].lower()]
        self._render_files(filtered)

    def _render_files(self, files):
        self.file_list.clear()
        for f in files:
            self.file_list.add_file(**f)

        if files:
            self.file_list.show()
            self.empty.hide()
        else:
            self.file_list.hide()
            self.empty.show()

Parameterized Components

from design_system import Card, CardHeader, Button, Badge

class ActionCard(Card):
    """Card with configurable actions."""

    def __init__(self, title, actions=None, badge=None):
        super().__init__()

        # Header with optional badge
        header = CardHeader(title=title)
        if badge:
            header.add_widget(Badge(badge["text"], variant=badge.get("variant", "primary")))
        self.add_widget(header)

        # Action buttons
        if actions:
            for action in actions:
                btn = Button(
                    action["label"],
                    variant=action.get("variant", "outline")
                )
                if "on_click" in action:
                    btn.clicked.connect(action["on_click"])
                self.add_widget(btn)

# Usage
card = ActionCard(
    title="Document",
    badge={"text": "New", "variant": "success"},
    actions=[
        {"label": "Edit", "variant": "primary", "on_click": edit_doc},
        {"label": "Delete", "variant": "danger", "on_click": delete_doc},
    ]
)

Layout Patterns

Master-Detail Layout

from PySide6.QtWidgets import QSplitter
from design_system import Panel, FileList, TextPanel

class MasterDetailView(QSplitter):
    def __init__(self):
        super().__init__()

        # Master (list)
        self.master = Panel()
        self.file_list = FileList()
        self.file_list.item_clicked.connect(self.show_detail)
        self.master.add_widget(self.file_list)
        self.addWidget(self.master)

        # Detail (content)
        self.detail = TextPanel()
        self.addWidget(self.detail)

        # Set proportions
        self.setSizes([300, 700])

    def show_detail(self, file_id):
        # Load and display file content
        content = self.load_file(file_id)
        self.detail.set_text(content)

Tab-Based Layout

from design_system import TabGroup, Panel

class TabbedView(Panel):
    def __init__(self):
        super().__init__()

        # Tab navigation
        self.tabs = TabGroup()
        self.tabs.add_tab("Overview", active=True)
        self.tabs.add_tab("Details")
        self.tabs.add_tab("History")
        self.tabs.tab_changed.connect(self.switch_tab)
        self.add_widget(self.tabs)

        # Content panels
        self.overview_panel = self.create_overview()
        self.details_panel = self.create_details()
        self.history_panel = self.create_history()

        self.panels = {
            "Overview": self.overview_panel,
            "Details": self.details_panel,
            "History": self.history_panel,
        }

        # Show initial panel
        self.current_panel = self.overview_panel
        self.add_widget(self.current_panel)

    def switch_tab(self, tab_name):
        # Hide current
        self.current_panel.hide()

        # Show new
        self.current_panel = self.panels[tab_name]
        self.current_panel.show()

Composition Best Practices

Do

  • Break complex UIs into reusable components
  • Use composition over inheritance
  • Pass configuration through constructor parameters
  • Keep components focused on single responsibility

Don't

  • Create deeply nested component hierarchies
  • Duplicate layout code across components
  • Tightly couple components to specific data structures
  • Mix business logic with presentation