Presentation Patterns
@thyris/ui-patterns combines primitives into repeatable interface structures. Patterns remain controlled, prop-driven presentation. The application adapts API data, owns permissions, performs side effects, and passes event handlers.
Keep @thyris/ui and @thyris/ui-patterns on the same release version.
Page and Navigation Patterns
| Pattern | Use It For | Important Inputs |
|---|---|---|
PageHeader | Consistent title, description, icon, actions, and breadcrumb framing. | title, description, icon, action, breadcrumbs. |
SectionNavigation | Controlled navigation between related sections. | Items, active item, selection or rendering callback. |
SidebarServiceSearch | Search and grouped service navigation inside the shared sidebar. | Groups, query, active item, empty text, render or navigation hooks. |
import {PageHeader} from "@thyris/ui-patterns"
import {Button} from "@thyris/ui"
import {Boxes} from "lucide-react"
export function CatalogHeader() {
return (
<PageHeader
title="Catalog"
description="Manage products available to customer and agent journeys."
icon={<Boxes aria-hidden="true" />}
breadcrumbs={[
{label: "Store", href: "/store"},
{label: "Catalog"},
]}
action={<Button type="button">Add product</Button>}
/>
)
}
The application owns actual route transitions and permission-filtered navigation items.
Collection and Table Patterns
| Pattern | Use It For | Important Inputs |
|---|---|---|
SearchFilterToolbar | Search, filters, and collection actions above a list or table. | Controlled value/change handler, placeholder, icon, filters, actions. |
BulkActionToolbar | Selection count and actions that affect selected rows. | Selection state, labels, actions, clear handler. |
TablePagination | Page navigation and optional page-size selection. | Page, page count, row count, page size, callbacks, labels. |
useTablePagination | Client-side pagination of an already available collection. | Items, controlled initial or current page configuration. |
OperationLogTableShell | Standard filters, states, table, and pagination for logs. | Toolbar, table content, loading/empty state, pagination. |
DomainTableShell | Standard page-level framing around domain tables. | Header context, toolbar, table, state, pagination. |
CollectionTableShell | General semantic alias of DomainTableShell. | Same as DomainTableShell. |
CatalogProductTableShell | Catalog-specific semantic alias. | Same as DomainTableShell. |
ProcurementTableShell | Procurement-specific semantic alias. | Same as DomainTableShell. |
Apply filters before pagination. Distinguish initial empty, filtered empty, loading, and error states. Pattern callbacks should call application-owned query or mutation logic.
Feedback and Utility Patterns
| Pattern | Use It For |
|---|---|
FeedbackAlert | Success, error, or informational feedback with consistent tone. |
StatusBadge | Textual status with default, success, warning, muted, or destructive tone. |
formatStatusLabel | Convert stable lowercase or underscore values into readable labels. |
EmptyState | Explain why no content is shown and provide a relevant next action. |
CopyableValue, CopyId, HeaderIdChip | Display and copy identifiers without rebuilding clipboard feedback. |
MetricCard | Present one operational metric, supporting detail, and optional trend or icon. |
import {EmptyState, StatusBadge} from "@thyris/ui-patterns"
export function ProviderState({count}: {count: number}) {
if (count === 0) {
return (
<EmptyState
title="No providers configured"
description="Add a provider before enabling enrichment jobs."
/>
)
}
return <StatusBadge value="active" tone="success" />
}
The application decides what a status means. The pattern only presents the value.
Selection and Form Patterns
| Pattern | Use It For |
|---|---|
SelectionListPanel | A labeled, searchable, keyboard-operable list of selectable items. |
ProviderSelector | Grouped provider choice using presentation-ready provider options. |
WizardDialogShell | Dialog framing, steps, body, and navigation actions for a controlled wizard. |
AppDialogProvider, useAppDialog | Application-level alert, confirmation, and prompt dialog orchestration. |
WizardDialogShell does not own validation, credentials, persistence, or route changes. Validate each step and perform side effects in application handlers.
Domain Presentation Patterns
Domain wording is allowed in these presentation models, but backend behavior is not.
| Pattern | Use It For |
|---|---|
EnrichmentProviderTable | Provider rows, status, usage, selection, and row or bulk controls. |
EnrichmentUsageChartPresentation | A prepared enrichment usage time series. |
EnrichmentUsageLog | Enrichment request history with filters and pagination. |
EnrichmentUsageMetricGroup | Quota, usage, and progress metric cards. |
MarketplaceRecentRuns | A concise table of recent marketplace executions. |
ProviderWizardPresentation | Visual steps and controlled fields for provider configuration. |
Adapt raw responses before passing them to these patterns:
const rows = apiProviders.map((provider) => ({
id: provider.id,
name: provider.displayName,
description: provider.description,
textModel: provider.textModel,
imageModel: provider.imageModel,
inputPricePerMillion: provider.inputPrice.toString(),
outputPricePerMillion: provider.outputPrice.toString(),
imagePrice: provider.imagePrice.toString(),
currency: provider.currency,
isDefault: provider.id === defaultProviderId,
}))
return (
<EnrichmentProviderTable
title="Providers"
description="Models and pricing available to enrichment jobs."
providers={rows}
onEdit={(provider) => openEditDialog(provider.id)}
onMakeDefault={(provider) => setDefaultMutation.mutate(provider.id)}
/>
)
The exact presentation interface is exported by the installed package and should be checked by TypeScript. Do not pass raw API models simply because some field names currently overlap.
Pattern Ownership Checklist
A shared pattern may:
- Render presentation-ready models.
- Hold local visual state that does not represent business truth.
- Invoke callbacks supplied by the consumer.
- Compose primitives and semantic tokens.
- Define safe responsive and accessible behavior.
A shared pattern must not:
- Fetch from a product API.
- Import a product router or route table.
- Read application authentication or permissions.
- Store or transmit credentials.
- Perform mutations or decide business state transitions.
- Import database or backend-only types.