Slots
Use this pattern when a component draws a fixed frame and each use fills in different parts of it. SlotPanel has a header, a body, and a footer. Each use fills them with <c-fill>, and the footer shows fallback text when a use leaves it out.
"""A panel with named slots and footer fallback content."""
from citry import Component, SlotInput
class SlotPanel(Component):
"""A styled panel with header, default body, and footer slots.
The footer slot ships fallback content, so a caller that omits the
footer still gets a sensible default rendering.
"""
class Kwargs:
pass
class Slots:
header: SlotInput
default: SlotInput
footer: SlotInput | None = None
template = """
<section class="slot-panel">
<header class="slot-panel__header">
<c-slot name="header" />
</header>
<div class="slot-panel__body">
<c-slot />
</div>
<footer class="slot-panel__footer">
<c-slot name="footer">
<span class="slot-panel__fallback">
No actions available
</span>
</c-slot>
</footer>
</section>
"""
css = """
.slot-panel {
max-width: 26rem;
border: 1px solid #d0d7de;
border-radius: 10px;
overflow: hidden;
font-family: system-ui, sans-serif;
box-shadow: 0 1px 3px rgba(27, 31, 36, 0.12);
}
.slot-panel__header {
padding: 0.75rem 1.25rem;
background: #0969da;
color: #ffffff;
font-weight: 600;
}
.slot-panel__body {
padding: 1.25rem;
color: #24292f;
line-height: 1.5;
}
.slot-panel__footer {
padding: 0.75rem 1.25rem;
background: #f6f8fa;
border-top: 1px solid #d0d7de;
display: flex;
gap: 0.5rem;
justify-content: flex-end;
}
.slot-panel__fallback {
color: #6e7781;
font-style: italic;
font-size: 0.9rem;
}
.slot-panel__button {
padding: 0.35rem 0.85rem;
border: 1px solid #d0d7de;
border-radius: 6px;
background: #ffffff;
color: #0969da;
font: inherit;
cursor: pointer;
}
"""
"""Standalone page that renders the SlotPanel example."""
from citry import Component
class SlotsPage(Component):
"""A full page showing named slots and footer fallback content."""
class Kwargs:
pass
class Slots:
pass
template = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Slots example</title>
<c-css />
<style>
body {
margin: 0;
padding: 1.5rem;
font-family: system-ui, sans-serif;
}
</style>
</head>
<body>
<main style="display: grid; gap: 1.5rem;">
<c-SlotPanel>
<c-fill name="header">
Project settings
</c-fill>
<c-fill name="default">
Configure how your project builds and deploys. Every
region of this panel is a named slot filled by the
caller.
</c-fill>
<c-fill name="footer">
<button class="slot-panel__button">Cancel</button>
<button class="slot-panel__button">Save</button>
</c-fill>
</c-SlotPanel>
<c-SlotPanel>
<c-fill name="header">
Read-only notice
</c-fill>
<c-fill name="default">
This panel omits the footer slot, so its footer shows
the component's own fallback content instead.
</c-fill>
</c-SlotPanel>
</main>
<c-js />
</body>
</html>
"""
The Slots class makes header and the default slot required and the footer optional (SlotInput | None = None). The content between <c-slot name="footer"> and </c-slot> is the fallback. The second panel on the page does not fill the footer, so it shows "No actions available".
For more about slots, see Slots.