Templates
Full-page layouts assembled from patterns and primitives. Each preview below is a live render using @mihcm/ui components. Copy the structure, replace the content, adjust to your domain.
Templates are grouped by purpose. Marketing templates are for public website and campaign surfaces; application templates are for authenticated product workflows.
Marketing templates
These pages use MiHCM primitives and semantic tokens for campaign and website work. They should stay separate from the core application layouts.
Product landing page
A compact marketing page with hero, product proof, module snapshot, and outcome CTAs. Use it for product pages, campaign pages, and partner-facing explainers.
import { Badge } from '@mihcm/ui/Badge';
import { Button } from '@mihcm/ui/Button';
import { Card } from '@mihcm/ui/Card';
import { StatCard } from '@mihcm/ui/StatCard';
import { Text } from '@mihcm/ui/Text';
export default function ProductLandingPage() {
return (
<main className="bg-background text-foreground">
<section className="grid gap-6 rounded-lg border border-border bg-card p-6 lg:grid-cols-2 lg:p-8">
<div>
<Badge variant="outline">MiHCM for growing teams</Badge>
<Text size="3xl" weight="bold" className="mt-4 block leading-tight">
Modern HR operations without fragmented tools.
</Text>
<Text size="body" tone="muted" className="mt-3 block">
Say the business outcome clearly and keep the CTA focused.
</Text>
<div className="mt-6 flex flex-wrap gap-3">
<Button>Book a demo</Button>
<Button variant="outline">See platform tour</Button>
</div>
</div>
<Card className="bg-muted p-4">
<Text size="body-sm" weight="semibold">Platform overview</Text>
<div className="mt-4 space-y-3">
{modules.map((module) => (
<div key={module.name} className="rounded-md border border-border bg-card p-3">
<Text size="body-sm" weight="medium">{module.name}</Text>
</div>
))}
</div>
</Card>
</section>
<section className="grid gap-3 border-x border-b border-border bg-muted p-4 sm:grid-cols-3">
<StatCard tone="primary" value="15+" label="Countries" />
<StatCard tone="accent" value="1M+" label="Records" />
<StatCard tone="success" value="99.9%" label="Uptime" />
</section>
</main>
);
}- Replace headline and supporting copy with one product outcome.
- Replace proof metrics with verified business claims.
- Keep all visual styling on semantic token classes.
Pricing and plan page
A marketing template for plan comparison. It provides a recommended plan, short feature list, and comparison table without requiring a custom visual system.
import { Badge } from '@mihcm/ui/Badge';
import { Button } from '@mihcm/ui/Button';
import { Card } from '@mihcm/ui/Card';
import { Text } from '@mihcm/ui/Text';
export default function PricingPage() {
return (
<main className="space-y-5 bg-background text-foreground">
<div className="max-w-2xl">
<Text size="2xl" weight="bold" className="block">
Choose the operating model that fits your HR team
</Text>
<Text size="body-sm" tone="muted" className="mt-2 block">
Make plan differences easy to compare before a buyer contacts sales.
</Text>
</div>
<div className="grid gap-4 lg:grid-cols-3">
{plans.map((plan) => (
<Card key={plan.name} className={plan.highlight ? 'border-primary shadow-mi-card' : undefined}>
<div className="p-5">
<div className="flex items-start justify-between gap-3">
<div>
<Text size="lg" weight="bold" className="block">{plan.name}</Text>
<Text size="body-sm" tone="muted" className="mt-1 block">{plan.description}</Text>
</div>
<Badge variant={plan.highlight ? 'default' : 'outline'}>{plan.label}</Badge>
</div>
<Button className="mt-5 w-full" variant={plan.highlight ? 'default' : 'outline'}>
Request pricing
</Button>
</div>
</Card>
))}
</div>
</main>
);
}- Use one highlighted plan only.
- Keep comparison rows short and factual.
- Avoid raw colour classes when emphasizing the recommended plan.
Application templates
These templates are for authenticated product experiences. They prioritize work density, role-specific actions, and predictable navigation.
Admin dashboard
The primary MiHCM admin surface. A page shell with stat cards, a scoped search bar, and a master-detail role editor.
import { PageShell } from '@mihcm/ui/PageShell';
import { TopBar, TopBarLogo, TopBarBackLink, TopBarNotification, TopBarProfile, TopBarDivider, TopBarAction } from '@mihcm/ui/TopBar';
import { MainSidebar } from '@mihcm/ui/MainSidebar';
import { TitleBar } from '@mihcm/ui/TitleBar';
import { StatCard } from '@mihcm/ui/StatCard';
import { SearchField } from '@mihcm/ui/SearchField';
import { Card } from '@mihcm/ui/Card';
import { Avatar, AvatarFallback, AvatarImage } from '@mihcm/ui/Avatar';
export default function AdminDashboard() {
const [active, setActive] = useState('security');
return (
<PageShell
topBar={
<TopBar
start={<><TopBarLogo /><TopBarBackLink>Back to main</TopBarBackLink><TopBarNotification icon={<BellIcon />} count={5} /></>}
end={<><TopBarProfile name="Good Morning Yashi" avatar={<Avatar><AvatarImage src="/people/alex-kim.svg" alt="Yashi" /><AvatarFallback>YA</AvatarFallback></Avatar>} /><TopBarDivider /><TopBarAction>Logout</TopBarAction></>}
/>
}
sidebar={<MainSidebar items={NAV} activeKey={active} onItemSelect={setActive} />}
titleBar={<TitleBar supertitle="User Administration" title="Security & Permissions" />}
>
{/* Search bar */}
<Card className="p-4 mb-4 flex items-center gap-4">
<SearchField placeholder="Search by name or email..." className="flex-1" />
</Card>
{/* Quick stats */}
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3 mb-4">
<StatCard tone="primary" value="6" label="Active Roles" />
<StatCard tone="accent" value="13,283" label="Total Users" />
<StatCard tone="success" value="16" label="Modules" />
</div>
{/* Master-detail card */}
<Card className="flex-1 flex flex-col md:flex-row min-h-0 overflow-hidden">
<aside className="w-full overflow-y-auto border-b border-secondary md:basis-72 md:border-b-0 md:border-r">
<RoleList />
</aside>
<main className="flex-1 bg-muted overflow-y-auto p-4">
<RoleEditor />
</main>
</Card>
</PageShell>
);
}- Replace NAV items with your module's sidebar entries.
- Replace StatCard values with your domain metrics.
- Replace RoleList / RoleEditor with your list and detail components.
Settings page
A single-column settings form with grouped sections. Uses SectionHeader to divide control groups and Switch / Input for toggles and fields.
General
Manage your account preferences.
import { PageShell } from '@mihcm/ui/PageShell';
import { TitleBar } from '@mihcm/ui/TitleBar';
import { Card, CardHeader, CardTitle, CardDescription } from '@mihcm/ui/Card';
import { SectionHeader } from '@mihcm/ui/SectionHeader';
import { Switch } from '@mihcm/ui/Switch';
import { Input } from '@mihcm/ui/Input';
import { Label } from '@mihcm/ui/Label';
import { Button } from '@mihcm/ui/Button';
import { Avatar, AvatarFallback, AvatarImage } from '@mihcm/ui/Avatar';
export default function SettingsPage() {
return (
<PageShell
topBar={
<TopBar
start={<><TopBarLogo /></>}
end={<><TopBarProfile avatar={<Avatar><AvatarImage src="/people/alex-kim.svg" alt="Yashi" /><AvatarFallback>YA</AvatarFallback></Avatar>} /><TopBarDivider /><TopBarAction>Logout</TopBarAction></>}
/>
}
titleBar={<TitleBar supertitle="Account" title="Settings" />}
>
<Card className="max-w-2xl">
<CardHeader>
<CardTitle>General</CardTitle>
<CardDescription>Manage your account preferences.</CardDescription>
</CardHeader>
<div className="px-6 pb-6 space-y-6">
<SectionHeader title="Profile" />
<div className="grid gap-4 sm:grid-cols-2">
<div>
<Label>First name</Label>
<Input placeholder="Yashi" className="mt-1.5" />
</div>
<div>
<Label>Last name</Label>
<Input placeholder="Alnashri" className="mt-1.5" />
</div>
</div>
<SectionHeader title="Notifications" description="Choose how you want to be notified." />
<div className="space-y-3">
<div className="flex items-center justify-between">
<Label>Email digest</Label>
<Switch checked={emailDigest} onCheckedChange={setEmailDigest} />
</div>
<div className="flex items-center justify-between">
<Label>Push notifications</Label>
<Switch checked={pushNotifications} onCheckedChange={setPushNotifications} />
</div>
</div>
<div className="flex justify-end gap-3 pt-4 border-t border-secondary">
<Button variant="outline">Cancel</Button>
<Button>Save changes</Button>
</div>
</div>
</Card>
</PageShell>
);
}- Add or remove SectionHeader groups to match your settings structure.
- Replace Input fields with your form state.
- Plug in your save handler on the primary Button.
Permission editor
A role configuration view with access-level controls and a permission list. Matches the MiHCM Security prototype's editor panel.
import { SectionHeader } from '@mihcm/ui/SectionHeader';
import { AccessLevelGroup } from '@mihcm/ui/AccessLevelGroup';
import { CheckboxGrid } from '@mihcm/ui/CheckboxGrid';
import { StatusBadge } from '@mihcm/ui/StatusBadge';
import { Text } from '@mihcm/ui/Text';
import { Button } from '@mihcm/ui/Button';
export default function PermissionEditor({ role }) {
return (
<div className="p-4 lg:p-6 space-y-6">
{/* Role header */}
<div className="flex items-center justify-between">
<div>
<Text size="lg" weight="bold" className="block">{role.name}</Text>
<Text size="body-sm" tone="muted" className="block mt-1">{role.description}</Text>
</div>
<StatusBadge tone={role.active ? 'success' : 'neutral'}>
{role.active ? 'Active' : 'Inactive'}
</StatusBadge>
</div>
{/* Module access */}
<SectionHeader
title="Module Access"
description="Set the access level for each module."
action={<Text size="label" tone="muted">3 of 16 enabled</Text>}
/>
<div className="space-y-3">
{role.modules.map(mod => (
<div key={mod.id} className="flex items-center justify-between">
<Text size="body-sm">{mod.name}</Text>
<AccessLevelGroup value={mod.level} onValueChange={v => updateModule(mod.id, v)} />
</div>
))}
</div>
{/* Fine-grained permissions */}
<SectionHeader title="Permissions" description="Toggle individual capabilities." />
<CheckboxGrid items={role.permissions} onChange={setPermissions} />
{/* Actions */}
<div className="flex justify-end gap-3 pt-4 border-t border-secondary">
<Button variant="outline">Discard</Button>
<Button>Save role</Button>
</div>
</div>
);
}- Replace role.modules and role.permissions with your data.
- Wire updateModule and setPermissions to your state management.
- Adjust the StatusBadge to reflect your domain's status model.
Product onboarding checklist
A guided setup template for administrators. Use it when a product area requires a sequence of required setup tasks before the user can operate confidently.
import { Button } from '@mihcm/ui/Button';
import { Card } from '@mihcm/ui/Card';
import { SectionHeader } from '@mihcm/ui/SectionHeader';
import { StatusBadge } from '@mihcm/ui/StatusBadge';
import { Text } from '@mihcm/ui/Text';
export default function ProductOnboarding() {
return (
<div className="grid gap-4 lg:grid-cols-3">
<Card className="p-5 lg:col-span-2">
<SectionHeader
title="Set up payroll operations"
description="Guide new administrators through the minimum viable setup."
action={<StatusBadge tone="info">3 of 5 complete</StatusBadge>}
/>
<div className="mt-5 space-y-3">
{tasks.map((task) => (
<div key={task.name} className="flex items-center justify-between rounded-md border border-border p-3">
<div>
<Text size="body-sm" weight="semibold" className="block">{task.name}</Text>
<Text size="caption" tone="muted" className="mt-1 block">{task.owner}</Text>
</div>
<StatusBadge tone={task.tone}>{task.state}</StatusBadge>
</div>
))}
</div>
</Card>
<Card className="p-5">
<Text size="lg" weight="bold" className="block">Next best action</Text>
<Text size="body-sm" tone="muted" className="mt-2 block">
Explain the next task and why it matters.
</Text>
<Button className="mt-5 w-full">Continue setup</Button>
</Card>
</div>
);
}- Replace tasks with your onboarding checklist.
- Use StatusBadge tones for state, not raw colours.
- Keep one next-best action visible beside the checklist.
Analytics workspace
A dashboard template for workforce metrics, priority insights, and export actions. Use it when users need to compare KPIs and investigate changes.
import { Button } from '@mihcm/ui/Button';
import { Card } from '@mihcm/ui/Card';
import { StatCard } from '@mihcm/ui/StatCard';
import { StatusBadge } from '@mihcm/ui/StatusBadge';
import { Text } from '@mihcm/ui/Text';
export default function AnalyticsWorkspace() {
return (
<div className="space-y-4">
<Card className="p-4">
<div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
<div>
<Text size="lg" weight="bold">Workforce analytics</Text>
<Text size="body-sm" tone="muted" className="mt-1 block">
Retention, hiring, and payroll indicators.
</Text>
</div>
<div className="flex flex-wrap gap-2">
<Button variant="outline">This quarter</Button>
<Button variant="outline">Export</Button>
</div>
</div>
</Card>
<div className="grid gap-3 sm:grid-cols-3">
<StatCard tone="primary" value="7.4%" label="Attrition" />
<StatCard tone="accent" value="18" label="Open roles" />
<StatCard tone="success" value="94%" label="Payroll SLA" />
</div>
<div className="grid gap-4 lg:grid-cols-2">
<Card className="p-5">
<Text size="body-sm" weight="semibold" className="block">Headcount trend</Text>
<div className="mt-4 space-y-3">
{teams.map((team) => (
<div key={team.name} className="flex items-center justify-between rounded-md border border-border p-3">
<Text size="body-sm" weight="medium">{team.name}</Text>
<StatusBadge tone={team.tone}>{team.trend}</StatusBadge>
</div>
))}
</div>
</Card>
</div>
</div>
);
}- Use StatCard for comparable headline metrics.
- Use StatusBadge for trend labels instead of hand-coded colour styles.
- Keep export and date-range actions in the workspace header.
What's next
- Browse all primitives: Components
- Study the token system: Tokens
- Render UI from a model: AI-UI