Templates
Full page examples composed entirely from existing Jetpack UI components — no one-off markup, no new components. Each template below is a realistic starting point you can copy into a project and adapt.
Login
A centered authentication card with email/password fields and a primary sign-in action.
Jetpack Labs
Sign in to your account
<div class="flex flex-col gap-4">
<FormGroup label="Email address" for="login-email">
<Input id="login-email" v-model="loginEmail" type="email" placeholder="you@example.com" />
</FormGroup>
<FormGroup label="Password" for="login-password">
<Input id="login-password" v-model="loginPassword" type="password" placeholder="••••••••" />
</FormGroup>
<Button class="w-full">Sign in</Button>
<div style="text-align:center">
<Link href="#" variant="subtle">Forgot password?</Link>
</div>
</div>
vue
<script setup>
import { ref } from 'vue'
const email = ref('')
const password = ref('')
</script>
<template>
<div class="flex justify-center">
<Card style="width:360px" :shadow="true">
<div style="text-align:center">
<div>Jetpack Labs</div>
<div>Sign in to your account</div>
</div>
<div class="flex flex-col gap-4">
<FormGroup label="Email address" for="email">
<Input id="email" v-model="email" type="email" placeholder="you@example.com" />
</FormGroup>
<FormGroup label="Password" for="password">
<Input id="password" v-model="password" type="password" placeholder="••••••••" />
</FormGroup>
<Button class="w-full">Sign in</Button>
<Link href="#" variant="subtle">Forgot password?</Link>
</div>
</Card>
</div>
</template>Settings
A settings form combining Input, Toggle, and Select for profile and preference fields, with a save action.
Account settings
<div class="flex flex-col gap-4">
<FormGroup label="Full name" for="settings-name">
<Input id="settings-name" v-model="settingsName" />
</FormGroup>
<FormGroup label="Email address" for="settings-email">
<Input id="settings-email" v-model="settingsEmail" type="email" />
</FormGroup>
<FormGroup label="Timezone" for="settings-tz">
<Select
id="settings-tz"
v-model="settingsTimezone"
:options="[
{ label: 'Mountain Time (Denver)', value: 'America/Denver' },
{ label: 'Pacific Time (Los Angeles)', value: 'America/Los_Angeles' },
{ label: 'Eastern Time (New York)', value: 'America/New_York' },
{ label: 'UTC', value: 'UTC' },
]"
/>
</FormGroup>
<div style="display:flex;flex-direction:column;gap:12px;padding-top:8px;border-top:1px solid #e5e7eb">
<Toggle v-model="settingsNotifications" label="Email notifications" />
<Toggle v-model="settingsMarketing" label="Product updates & marketing" />
</div>
</div>
<template #footer>
<Button variant="secondary">Cancel</Button>
<Button>Save changes</Button>
</template>
vue
<script setup>
import { ref } from 'vue'
const name = ref('Jamie Rivera')
const email = ref('jamie@jetpacklabs.com')
const notifications = ref(true)
const marketing = ref(false)
const timezone = ref('America/Denver')
</script>
<template>
<Card>
<template #header>Account settings</template>
<div class="flex flex-col gap-4">
<FormGroup label="Full name" for="name">
<Input id="name" v-model="name" />
</FormGroup>
<FormGroup label="Email address" for="email">
<Input id="email" v-model="email" type="email" />
</FormGroup>
<FormGroup label="Timezone" for="tz">
<Select v-model="timezone" :options="timezoneOptions" />
</FormGroup>
<Toggle v-model="notifications" label="Email notifications" />
<Toggle v-model="marketing" label="Product updates & marketing" />
</div>
<template #footer>
<Button variant="secondary">Cancel</Button>
<Button>Save changes</Button>
</template>
</Card>
</template>Dashboard
A row of stat cards summarizing key metrics, followed by a DataTable of underlying records.
Total Production
4,820 t
Throughput
312 t/h
↑ 8.5vs last week
Active Equipment
18 / 22
Downtime
2.1 hrs
↓ 4.2vs last week
<Card>
<template #header>
<span style="font-size:15px;font-weight:600;color:#111827">Equipment status</span>
</template>
<DataTable
:columns="dashColumns"
:rows="dashRows"
:total="dashRows.length"
:page="dashPage"
:per-page="DASH_PER_PAGE"
@update:page="dashPage = $event"
>
<template #cell-status="{ value }">
<Badge :variant="dashStatusVariant(value)"></Badge>
</template>
</DataTable>
</Card>
vue
<script setup>
import { ref } from 'vue'
const columns = [
{ key: 'name', label: 'Name' },
{ key: 'status', label: 'Status' },
{ key: 'location', label: 'Location' },
{ key: 'updated', label: 'Last Updated', align: 'right' },
]
const rows = ref([...])
const page = ref(1)
const statusVariant = (s) =>
s === 'Running' ? 'success' : s === 'Down' ? 'danger' : 'neutral'
</script>
<template>
<div class="flex flex-col gap-6">
<div class="flex flex-wrap gap-4">
<StatCard label="Total Production" value="4,820 t" />
<StatCard label="Throughput" value="312 t/h" :trend="8.5" trend-label="vs last week" />
<StatCard label="Active Equipment" value="18 / 22" />
<StatCard label="Downtime" value="2.1 hrs" :trend="-4.2" trend-label="vs last week" />
</div>
<Card>
<template #header>Equipment status</template>
<DataTable
:columns="columns"
:rows="rows"
:total="rows.length"
:page="page"
:per-page="4"
@update:page="page = $event"
>
<template #cell-status="{ value }">
<Badge :variant="statusVariant(value)">{{ value }}</Badge>
</template>
</DataTable>
</Card>
</div>
</template>Empty State
EmptyState inside a Card, paired with a call-to-action button to create the first record.
No equipment records
Add your first piece of equipment to start tracking status and production.
vue
<template>
<Card>
<EmptyState
icon="🏗️"
title="No equipment records"
description="Add your first piece of equipment to start tracking status and production."
>
<template #action>
<Button>Add equipment</Button>
</template>
</EmptyState>
</Card>
</template>