Stepper

A component for displaying steps in a process or wizard

Orientations

Horizontal and vertical layout options.


Code Svelte
1
2<script lang="ts">
3  import { Button, CardPrimitives, Stepper } from "@kareyes/aether";
4
5  const { Card, CardHeader, CardTitle, CardDescription, CardContent } = CardPrimitives;
6
7  let basicStep = $state(1);
8  let verticalStep = $state(0);
9</script>
10
11<div class="grid gap-8 lg:grid-cols-2">
12  <Card>
13    <CardHeader>
14      <CardTitle>Horizontal Stepper</CardTitle>
15      <CardDescription>Default layout, perfect for wide screens</CardDescription>
16    </CardHeader>
17    <CardContent class="space-y-6">
18      <Stepper
19        bind:activeStep={basicStep}
20        steps={[
21          { label: "Step 1", description: "Choose a plan" },
22          { label: "Step 2", description: "Enter details" },
23          { label: "Step 3", description: "Confirm" },
24        ]}
25      />
26      <div class="flex gap-3">
27        <Button variant="outline" disabled={basicStep === 0} onclick={() => basicStep--}>
28          Previous
29        </Button>
30        <Button disabled={basicStep === 2} onclick={() => basicStep++}>
31          Next
32        </Button>
33      </div>
34    </CardContent>
35  </Card>
36
37  <Card>
38    <CardHeader>
39      <CardTitle>Vertical Stepper</CardTitle>
40      <CardDescription>Great for mobile and detailed steps</CardDescription>
41    </CardHeader>
42    <CardContent class="space-y-6">
43      <Stepper
44        orientation="vertical"
45        bind:activeStep={verticalStep}
46        steps={[
47          { label: "Personal Info", description: "Enter your basic information" },
48          { label: "Address", description: "Add your address details" },
49          { label: "Review", description: "Review and submit" },
50        ]}
51      />
52      <div class="flex gap-3">
53        <Button variant="outline" disabled={verticalStep === 0} onclick={() => verticalStep--}>
54          Previous
55        </Button>
56        <Button disabled={verticalStep === 2} onclick={() => verticalStep++}>
57          Next
58        </Button>
59      </div>
60    </CardContent>
61  </Card>
62</div>

Sizes & Variants

Different sizes and visual styles.


Code Svelte
1
2<script lang="ts">
3  import { CardPrimitives, Stepper } from "@kareyes/aether";
4
5  const { Card, CardHeader, CardTitle, CardDescription, CardContent } = CardPrimitives;
6</script>
7
8<div class="grid gap-6">
9  <Card>
10    <CardHeader><CardTitle>Extra Small Size</CardTitle></CardHeader>
11    <CardContent>
12      <Stepper size="xs" activeStep={1} steps={[
13        { label: "Start" },
14        { label: "Progress" },
15        { label: "Complete" },
16      ]} />
17    </CardContent>
18  </Card>
19
20  <Card>
21    <CardHeader><CardTitle>Small Size</CardTitle></CardHeader>
22    <CardContent>
23      <Stepper size="sm" activeStep={1} steps={[
24        { label: "Start" },
25        { label: "Progress" },
26        { label: "Complete" },
27      ]} />
28    </CardContent>
29  </Card>
30
31  <Card>
32    <CardHeader><CardTitle>Default Size</CardTitle></CardHeader>
33    <CardContent>
34      <Stepper size="default" activeStep={1} steps={[
35        { label: "Start" },
36        { label: "Progress" },
37        { label: "Complete" },
38      ]} />
39    </CardContent>
40  </Card>
41
42  <Card>
43    <CardHeader><CardTitle>Large Size</CardTitle></CardHeader>
44    <CardContent>
45      <Stepper size="lg" activeStep={1} steps={[
46        { label: "Start" },
47        { label: "Progress" },
48        { label: "Complete" },
49      ]} />
50    </CardContent>
51  </Card>
52
53  <Card>
54    <CardHeader><CardTitle>Outline Variant</CardTitle></CardHeader>
55    <CardContent>
56      <Stepper variant="outline" activeStep={1} steps={[
57        { label: "Start", description: "Begin process" },
58        { label: "Progress", description: "In progress" },
59        { label: "Complete", description: "Finish" },
60      ]} />
61    </CardContent>
62  </Card>
63
64  <Card>
65    <CardHeader><CardTitle>Ghost Variant</CardTitle></CardHeader>
66    <CardContent>
67      <Stepper variant="ghost" activeStep={1} steps={[
68        { label: "Start", description: "Begin process" },
69        { label: "Progress", description: "In progress" },
70        { label: "Complete", description: "Finish" },
71      ]} />
72    </CardContent>
73  </Card>
74
75  <Card>
76    <CardHeader>
77      <CardTitle>Flat Variant</CardTitle>
78      <CardDescription>Horizontal progress bar style</CardDescription>
79    </CardHeader>
80    <CardContent class="pt-8 mt-8">
81      <Stepper variant="flat" activeStep={1} steps={[
82        { label: "Personal Info", description: "Completed" },
83        { label: "Education", description: "Completed" },
84        { label: "Company", description: "Pending" },
85        { label: "Testing", description: "Pending" },
86        { label: "Review", description: "Pending" },
87      ]} />
88    </CardContent>
89  </Card>
90</div>

Interactive Features

Clickable steps and custom icons.


Code Svelte
1
2<script lang="ts">
3  import { CardPrimitives, Stepper } from "@kareyes/aether";
4  import { User, CreditCard, CircleCheck } from "@lucide/svelte";
5
6  const { Card, CardHeader, CardTitle, CardDescription, CardContent } = CardPrimitives;
7
8  let clickableStep = $state(1);
9  let result = $state("");
10</script>
11
12<div class="grid gap-6">
13  <Card>
14    <CardHeader>
15      <CardTitle>Clickable Steps</CardTitle>
16      <CardDescription>Click on any step to navigate directly</CardDescription>
17    </CardHeader>
18    <CardContent>
19      <Stepper
20        clickable
21        bind:activeStep={clickableStep}
22        onStepClick={(step: number) => result = `Clicked step ${step + 1}`}
23        steps={[
24          { label: "Step 1", description: "First step" },
25          { label: "Step 2", description: "Second step" },
26          { label: "Step 3", description: "Third step" },
27        ]}
28      />
29    </CardContent>
30  </Card>
31
32  <Card>
33    <CardHeader>
34      <CardTitle>With Custom Icons</CardTitle>
35      <CardDescription>Pass icon components via the steps array</CardDescription>
36    </CardHeader>
37    <CardContent>
38      <Stepper
39        activeStep={1}
40        steps={[
41          { label: "Account", description: "Create account", icon: User },
42          { label: "Payment", description: "Add payment", icon: CreditCard },
43          { label: "Done", description: "All set!", icon: CircleCheck },
44        ]}
45      />
46    </CardContent>
47  </Card>
48
49  <Card>
50    <CardHeader>
51      <CardTitle>Numbers Only</CardTitle>
52      <CardDescription>Minimal stepper with just numbers</CardDescription>
53    </CardHeader>
54    <CardContent>
55      <Stepper activeStep={2} steps={[{}, {}, {}, {}]} />
56    </CardContent>
57  </Card>
58</div>

Step States

Per-step error, loading, and disabled states override the normal completed/active/inactive appearance. Priority: disabled β†’ error β†’ loading β†’ completed β†’ active β†’ inactive.


Code Svelte
1
2<script lang="ts">
3  import { CardPrimitives, Stepper } from "@kareyes/aether";
4  import { ShoppingCart, CreditCard, CircleCheck } from "@lucide/svelte";
5
6  const { Card, CardHeader, CardTitle, CardDescription, CardContent } = CardPrimitives;
7</script>
8
9<div class="grid gap-6">
10  <Card>
11    <CardHeader>
12      <CardTitle>Error State</CardTitle>
13      <CardDescription>Renders a red X icon with destructive colors</CardDescription>
14    </CardHeader>
15    <CardContent>
16      <Stepper
17        activeStep={1}
18        steps={[
19          { label: "Upload", description: "File uploaded" },
20          { label: "Validate", description: "Checksum failed", error: true },
21          { label: "Process", description: "Waiting" },
22        ]}
23      />
24    </CardContent>
25  </Card>
26
27  <Card>
28    <CardHeader>
29      <CardTitle>Loading State</CardTitle>
30      <CardDescription>Renders a spinning loader with active colors</CardDescription>
31    </CardHeader>
32    <CardContent>
33      <Stepper
34        activeStep={1}
35        steps={[
36          { label: "Upload", description: "Done" },
37          { label: "Processing", description: "Converting file…", loading: true },
38          { label: "Complete", description: "Waiting" },
39        ]}
40      />
41    </CardContent>
42  </Card>
43
44  <Card>
45    <CardHeader>
46      <CardTitle>Disabled Steps</CardTitle>
47      <CardDescription>Grayed out and not clickable even when the stepper is clickable</CardDescription>
48    </CardHeader>
49    <CardContent>
50      <Stepper
51        activeStep={1}
52        clickable
53        steps={[
54          { label: "Starter", description: "Current plan" },
55          { label: "Pro", description: "Active step" },
56          { label: "Enterprise", description: "Contact sales", disabled: true },
57          { label: "Custom", description: "Contact sales", disabled: true },
58        ]}
59      />
60    </CardContent>
61  </Card>
62
63  <Card>
64    <CardHeader>
65      <CardTitle>Mixed States</CardTitle>
66      <CardDescription>error, loading, disabled, and normal steps together</CardDescription>
67    </CardHeader>
68    <CardContent>
69      <Stepper
70        activeStep={2}
71        variant="ghost"
72        steps={[
73          { label: "Upload", description: "Done" },
74          { label: "Validate", description: "Checksum error", error: true },
75          { label: "Process", description: "Converting…", loading: true },
76          { label: "Review", description: "Pending" },
77          { label: "Deploy", description: "Restricted", disabled: true },
78        ]}
79      />
80    </CardContent>
81  </Card>
82
83  <Card>
84    <CardHeader>
85      <CardTitle>Icons + States</CardTitle>
86      <CardDescription>Custom icons still render in inactive/completed β€” error and loading override them</CardDescription>
87    </CardHeader>
88    <CardContent>
89      <Stepper
90        activeStep={1}
91        steps={[
92          { label: "Cart", description: "Items ready", icon: ShoppingCart },
93          { label: "Payment", description: "Card declined", icon: CreditCard, error: true },
94          { label: "Confirm", description: "Waiting", icon: CircleCheck, disabled: true },
95        ]}
96      />
97    </CardContent>
98  </Card>
99</div>

Circular Progress Mode

mobileLayout="circular" β€” below md (768px) the step list is replaced by a radial progress ring. Desktop stays horizontal. Resize the browser to see the switch.


Code Svelte
1
2<script lang="ts">
3  import { CardPrimitives, Stepper } from "@kareyes/aether";
4  import { ShoppingCart, CreditCard, CircleCheck } from "@lucide/svelte";
5
6  const { Card, CardHeader, CardTitle, CardDescription, CardContent } = CardPrimitives;
7
8  let circularStep = $state(0);
9  let circularAlwaysStep = $state(1);
10</script>
11
12<div class="grid gap-6">
13  <Card>
14    <CardHeader>
15      <CardTitle>Basic Circular (resize to see)</CardTitle>
16      <CardDescription>Switches to ring below md breakpoint</CardDescription>
17    </CardHeader>
18    <CardContent>
19      <Stepper
20        bind:activeStep={circularStep}
21        clickable
22        mobileLayout="circular"
23        steps={[
24          { label: "Account", description: "Create your account" },
25          { label: "Profile", description: "Complete your profile" },
26          { label: "Billing", description: "Add a payment method" },
27          { label: "Review", description: "Confirm your details" },
28          { label: "Done", description: "All set!" },
29        ]}
30      />
31    </CardContent>
32  </Card>
33
34  <Card>
35    <CardHeader>
36      <CardTitle>Circular Always</CardTitle>
37      <CardDescription>circularAlways β€” ring visible at all breakpoints</CardDescription>
38    </CardHeader>
39    <CardContent>
40      <Stepper
41        bind:activeStep={circularAlwaysStep}
42        clickable
43        mobileLayout="circular"
44        circularAlways
45        steps={[
46          { label: "Plan", description: "Define scope" },
47          { label: "Build", description: "Implement features" },
48          { label: "Test", description: "QA and review" },
49          { label: "Ship", description: "Deploy to production" },
50        ]}
51      />
52    </CardContent>
53  </Card>
54
55  <Card>
56    <CardHeader>
57      <CardTitle>Large Ring (circularSize=200)</CardTitle>
58      <CardDescription>Custom ring diameter</CardDescription>
59    </CardHeader>
60    <CardContent>
61      <Stepper
62        mobileLayout="circular"
63        circularAlways
64        circularSize={200}
65        activeStep={1}
66        steps={[
67          { label: "Research", description: "Gather requirements" },
68          { label: "Design", description: "Create wireframes" },
69          { label: "Implement", description: "Write the code" },
70          { label: "Launch", description: "Go live πŸš€" },
71        ]}
72      />
73    </CardContent>
74  </Card>
75
76  <Card>
77    <CardHeader>
78      <CardTitle>Non-expandable Ring</CardTitle>
79      <CardDescription>circularExpandable=false β€” no drawer on click</CardDescription>
80    </CardHeader>
81    <CardContent>
82      <Stepper
83        activeStep={1}
84        mobileLayout="circular"
85        circularAlways
86        circularExpandable={false}
87        steps={[
88          { label: "Step 1", description: "First step" },
89          { label: "Step 2", description: "Second step" },
90          { label: "Step 3", description: "Third step" },
91          { label: "Step 4", description: "Final step" },
92        ]}
93      />
94    </CardContent>
95  </Card>
96</div>

Practical Examples

Real-world use cases and implementations.


Code Svelte
1
2<script lang="ts">
3  import { Button, Input, Label, Textarea, CardPrimitives, Stepper } from "@kareyes/aether";
4  import { User, CreditCard, CircleCheck, ShoppingCart, Package, Mail, Briefcase, FileText } from "@lucide/svelte";
5
6  const { Card, CardHeader, CardTitle, CardDescription, CardContent } = CardPrimitives;
7
8  // Registration flow
9  let registrationStep = $state(0);
10  let registrationData = $state({ email: "", password: "", name: "", phone: "", address: "" });
11
12  function nextRegistrationStep() { if (registrationStep < 2) registrationStep++; }
13  function previousRegistrationStep() { if (registrationStep > 0) registrationStep--; }
14
15  // Checkout flow
16  let checkoutStep = $state(1);
17  let checkoutData = $state({ items: 3, total: "$127.50", cardNumber: "", shippingMethod: "" });
18
19  function nextCheckoutStep() { if (checkoutStep < 3) checkoutStep++; }
20  function previousCheckoutStep() { if (checkoutStep > 0) checkoutStep--; }
21
22  // Job application flow
23  let applicationStep = $state(0);
24  let applicationData = $state({ fullName: "", email: "", position: "", experience: "", education: "" });
25
26  function nextApplicationStep() { if (applicationStep < 2) applicationStep++; }
27  function previousApplicationStep() { if (applicationStep > 0) applicationStep--; }
28</script>
29
30<div class="grid gap-6">
31  <!-- Registration Flow -->
32  <Card>
33    <CardHeader>
34      <CardTitle>Registration Flow</CardTitle>
35      <CardDescription>Multi-step account creation process</CardDescription>
36    </CardHeader>
37    <CardContent class="space-y-6">
38      <Stepper
39        bind:activeStep={registrationStep}
40        steps={[
41          { label: "Account", description: "Create your account", icon: Mail },
42          { label: "Profile", description: "Personal information", icon: User },
43          { label: "Complete", description: "Review and finish", icon: CircleCheck },
44        ]}
45      />
46
47      <div class="min-h-[200px]">
48        {#if registrationStep === 0}
49          <div class="space-y-4">
50            <h3 class="text-lg font-semibold">Create Your Account</h3>
51            <div class="space-y-2">
52              <Label for="reg-email">Email</Label>
53              <Input id="reg-email" type="email" bind:value={registrationData.email} placeholder="john@example.com" />
54            </div>
55            <div class="space-y-2">
56              <Label for="reg-password">Password</Label>
57              <Input id="reg-password" type="password" bind:value={registrationData.password} placeholder="β€’β€’β€’β€’β€’β€’β€’β€’" />
58            </div>
59          </div>
60        {:else if registrationStep === 1}
61          <div class="space-y-4">
62            <h3 class="text-lg font-semibold">Personal Information</h3>
63            <div class="space-y-2">
64              <Label for="reg-name">Full Name</Label>
65              <Input id="reg-name" bind:value={registrationData.name} placeholder="John Doe" />
66            </div>
67            <div class="space-y-2">
68              <Label for="reg-phone">Phone Number</Label>
69              <Input id="reg-phone" bind:value={registrationData.phone} placeholder="+1 (555) 000-0000" />
70            </div>
71          </div>
72        {:else}
73          <div class="space-y-4">
74            <h3 class="text-lg font-semibold">Review Your Information</h3>
75            <dl class="space-y-3">
76              <div><dt class="font-medium">Email:</dt><dd class="text-muted-foreground">{registrationData.email || "Not provided"}</dd></div>
77              <div><dt class="font-medium">Name:</dt><dd class="text-muted-foreground">{registrationData.name || "Not provided"}</dd></div>
78              <div><dt class="font-medium">Phone:</dt><dd class="text-muted-foreground">{registrationData.phone || "Not provided"}</dd></div>
79            </dl>
80          </div>
81        {/if}
82      </div>
83
84      <div class="flex gap-3">
85        {#if registrationStep > 0}
86          <Button variant="outline" onclick={previousRegistrationStep}>Previous</Button>
87        {/if}
88        {#if registrationStep < 2}
89          <Button onclick={nextRegistrationStep}>Next</Button>
90        {:else}
91          <Button>Complete Registration</Button>
92        {/if}
93      </div>
94    </CardContent>
95  </Card>
96
97  <!-- Checkout Process -->
98  <Card>
99    <CardHeader>
100      <CardTitle>Checkout Process</CardTitle>
101      <CardDescription>E-commerce checkout flow with vertical stepper</CardDescription>
102    </CardHeader>
103    <CardContent class="space-y-6">
104      <div class="grid gap-6 lg:grid-cols-[300px_1fr]">
105        <Stepper
106          orientation="vertical"
107          bind:activeStep={checkoutStep}
108          size="sm"
109          steps={[
110            { label: "Cart", description: "Review items", icon: ShoppingCart },
111            { label: "Payment", description: "Payment details", icon: CreditCard },
112            { label: "Shipping", description: "Shipping method", icon: Package },
113            { label: "Confirm", description: "Place order", icon: CircleCheck },
114          ]}
115        />
116
117        <div class="min-h-[200px]">
118          {#if checkoutStep === 0}
119            <div class="space-y-4">
120              <h3 class="text-lg font-semibold">Your Cart</h3>
121              <p class="text-sm text-muted-foreground">You have {checkoutData.items} items in your cart</p>
122              <div class="text-2xl font-bold">{checkoutData.total}</div>
123            </div>
124          {:else if checkoutStep === 1}
125            <div class="space-y-4">
126              <h3 class="text-lg font-semibold">Payment Information</h3>
127              <div class="space-y-2">
128                <Label for="card-number">Card Number</Label>
129                <Input id="card-number" bind:value={checkoutData.cardNumber} placeholder="1234 5678 9012 3456" />
130              </div>
131              <div class="grid grid-cols-2 gap-4">
132                <div class="space-y-2">
133                  <Label for="expiry">Expiry Date</Label>
134                  <Input id="expiry" placeholder="MM/YY" />
135                </div>
136                <div class="space-y-2">
137                  <Label for="cvv">CVV</Label>
138                  <Input id="cvv" placeholder="123" />
139                </div>
140              </div>
141            </div>
142          {:else if checkoutStep === 2}
143            <div class="space-y-4">
144              <h3 class="text-lg font-semibold">Shipping Method</h3>
145              <div class="space-y-2">
146                <label class="flex items-center gap-3 rounded-lg border p-4 cursor-pointer hover:bg-muted">
147                  <input type="radio" name="shipping" value="standard" bind:group={checkoutData.shippingMethod} />
148                  <div>
149                    <div class="font-medium">Standard Shipping</div>
150                    <div class="text-sm text-muted-foreground">5-7 business days - Free</div>
151                  </div>
152                </label>
153                <label class="flex items-center gap-3 rounded-lg border p-4 cursor-pointer hover:bg-muted">
154                  <input type="radio" name="shipping" value="express" bind:group={checkoutData.shippingMethod} />
155                  <div>
156                    <div class="font-medium">Express Shipping</div>
157                    <div class="text-sm text-muted-foreground">2-3 business days - $12.99</div>
158                  </div>
159                </label>
160              </div>
161            </div>
162          {:else}
163            <div class="space-y-4">
164              <h3 class="text-lg font-semibold">Review Order</h3>
165              <dl class="space-y-2">
166                <div class="flex justify-between"><dt>Items:</dt><dd>{checkoutData.items}</dd></div>
167                <div class="flex justify-between"><dt>Subtotal:</dt><dd>{checkoutData.total}</dd></div>
168                <div class="flex justify-between"><dt>Shipping:</dt><dd>{checkoutData.shippingMethod === "express" ? "$12.99" : "Free"}</dd></div>
169                <div class="flex justify-between text-lg font-bold border-t pt-2">
170                  <dt>Total:</dt>
171                  <dd>{checkoutData.shippingMethod === "express" ? "$140.49" : checkoutData.total}</dd>
172                </div>
173              </dl>
174            </div>
175          {/if}
176        </div>
177      </div>
178
179      <div class="flex gap-3">
180        {#if checkoutStep > 0}
181          <Button variant="outline" onclick={previousCheckoutStep}>Previous</Button>
182        {/if}
183        {#if checkoutStep < 3}
184          <Button onclick={nextCheckoutStep}>Continue</Button>
185        {:else}
186          <Button>Place Order</Button>
187        {/if}
188      </div>
189    </CardContent>
190  </Card>
191
192  <!-- Job Application -->
193  <Card>
194    <CardHeader>
195      <CardTitle>Job Application</CardTitle>
196      <CardDescription>Multi-step job application form</CardDescription>
197    </CardHeader>
198    <CardContent class="space-y-6">
199      <Stepper
200        bind:activeStep={applicationStep}
201        clickable
202        steps={[
203          { label: "Personal", description: "Basic info", icon: User },
204          { label: "Experience", description: "Work history", icon: Briefcase },
205          { label: "Review", description: "Submit", icon: FileText },
206        ]}
207      />
208
209      <div class="min-h-[200px]">
210        {#if applicationStep === 0}
211          <div class="space-y-4">
212            <h3 class="text-lg font-semibold">Personal Information</h3>
213            <div class="grid gap-4 sm:grid-cols-2">
214              <div class="space-y-2">
215                <Label for="app-name">Full Name</Label>
216                <Input id="app-name" bind:value={applicationData.fullName} />
217              </div>
218              <div class="space-y-2">
219                <Label for="app-email">Email</Label>
220                <Input id="app-email" type="email" bind:value={applicationData.email} />
221              </div>
222            </div>
223            <div class="space-y-2">
224              <Label for="app-position">Position Applied For</Label>
225              <Input id="app-position" bind:value={applicationData.position} />
226            </div>
227          </div>
228        {:else if applicationStep === 1}
229          <div class="space-y-4">
230            <h3 class="text-lg font-semibold">Experience & Education</h3>
231            <div class="space-y-2">
232              <Label for="app-experience">Work Experience</Label>
233              <Textarea id="app-experience" bind:value={applicationData.experience} rows={4} />
234            </div>
235            <div class="space-y-2">
236              <Label for="app-education">Education</Label>
237              <Textarea id="app-education" bind:value={applicationData.education} rows={3} />
238            </div>
239          </div>
240        {:else}
241          <div class="space-y-4">
242            <h3 class="text-lg font-semibold">Review Application</h3>
243            <dl class="space-y-2">
244              <div><dt class="font-medium">Name:</dt><dd class="text-muted-foreground">{applicationData.fullName || "Not provided"}</dd></div>
245              <div><dt class="font-medium">Email:</dt><dd class="text-muted-foreground">{applicationData.email || "Not provided"}</dd></div>
246              <div><dt class="font-medium">Position:</dt><dd class="text-muted-foreground">{applicationData.position || "Not provided"}</dd></div>
247            </dl>
248          </div>
249        {/if}
250      </div>
251
252      <div class="flex gap-3">
253        {#if applicationStep > 0}
254          <Button variant="outline" onclick={previousApplicationStep}>Previous</Button>
255        {/if}
256        {#if applicationStep < 2}
257          <Button onclick={nextApplicationStep}>Next</Button>
258        {:else}
259          <Button>Submit Application</Button>
260        {/if}
261      </div>
262    </CardContent>
263  </Card>
264</div>
265
266
267
268
269

Custom Label & Description

Using children snippet for custom step content.


Code Svelte
1
2<script lang="ts">
3  import { CardPrimitives, StepperPrimitives } from "@kareyes/aether";
4   import { User, Settings, CircleCheck, Package, ShoppingCart, MapPin, FileText, Briefcase, GraduationCap } from "@kareyes/aether/icons";
5
6  const { StepperRoot, StepperStep, StepperSeparator } = StepperPrimitives;
7  const { Card, CardHeader, CardTitle, CardDescription, CardContent } = CardPrimitives;
8</script>
9
10<Card>
11  <CardHeader>
12    <CardTitle>Custom Rich Content</CardTitle>
13    <CardDescription>Use StepperRoot for per-step children snippets and rich content</CardDescription>
14  </CardHeader>
15  <CardContent class="space-y-6">
16    <StepperRoot activeStep={1}>
17      <StepperStep step={0}>
18        {#snippet icon()}
19          <User class="size-4" />
20        {/snippet}
21        <div class="space-y-1">
22          <div class="font-medium">Account Setup</div>
23          <div class="text-sm text-muted-foreground">Create your credentials</div>
24        </div>
25      </StepperStep>
26      <StepperSeparator completed />
27      <StepperStep step={1}>
28        {#snippet icon()}
29          <Settings class="size-4" />
30        {/snippet}
31        <div class="space-y-1">
32          <div class="font-medium flex items-center gap-2">
33            Configuration
34            <span class="text-xs bg-primary/10 text-primary px-2 py-0.5 rounded-full">Active</span>
35          </div>
36          <div class="text-sm text-muted-foreground">Customize your settings</div>
37        </div>
38      </StepperStep>
39      <StepperSeparator />
40      <StepperStep step={2}>
41        {#snippet icon()}
42          <CircleCheck class="size-4" />
43        {/snippet}
44        <div class="space-y-1">
45          <div class="font-medium">Completion</div>
46          <div class="text-sm text-muted-foreground">Review and launch</div>
47        </div>
48      </StepperStep>
49    </StepperRoot>
50  </CardContent>
51</Card>
52  <Card>
53    <CardHeader>
54      <CardTitle>Custom Styling</CardTitle>
55      <CardDescription>Apply custom styles and components within step content</CardDescription>
56    </CardHeader>
57    <CardContent class="space-y-6">
58      <div class="max-w-md">
59        <StepperRoot orientation="vertical" activeStep={1} size="sm">
60          <StepperStep step={0}>
61            {#snippet icon()}
62              <Package class="size-3" />
63            {/snippet}
64            <div class="space-y-2 pb-4">
65              <div class="font-semibold text-base">Order Placed</div>
66              <div class="text-sm text-muted-foreground">
67                Your order <span class="font-mono text-foreground">#ORD-12345</span> has been confirmed
68              </div>
69              <div class="text-xs text-muted-foreground">Jan 14, 2026 β€’ 10:30 AM</div>
70            </div>
71          </StepperStep>
72          <StepperSeparator completed />
73          <StepperStep step={1}>
74            {#snippet icon()}
75              <ShoppingCart class="size-3" />
76            {/snippet}
77            <div class="space-y-2 pb-4">
78              <div class="font-semibold text-base flex items-center gap-2">
79                Processing
80                <span class="inline-flex h-2 w-2 rounded-full bg-primary animate-pulse"></span>
81              </div>
82              <div class="text-sm text-muted-foreground">Your order is being prepared for shipment</div>
83              <div class="text-xs text-muted-foreground">Estimated: 2-3 hours</div>
84            </div>
85          </StepperStep>
86          <StepperSeparator />
87          <StepperStep step={2}>
88            {#snippet icon()}
89              <MapPin class="size-3" />
90            {/snippet}
91            <div class="space-y-2">
92              <div class="font-semibold text-base">Out for Delivery</div>
93              <div class="text-sm text-muted-foreground">Package will arrive at your address</div>
94              <div class="text-xs text-muted-foreground">Pending</div>
95            </div>
96          </StepperStep>
97        </StepperRoot>
98      </div>
99    </CardContent>
100  </Card>
101
102  <div class="grid gap-6 md:grid-cols-2">
103    <Card>
104      <CardHeader>
105        <CardTitle>With Status Badges</CardTitle>
106      </CardHeader>
107      <CardContent>
108        <StepperRoot activeStep={1} variant="outline">
109          <StepperStep step={0}>
110            {#snippet icon()}
111              <FileText class="size-4" />
112            {/snippet}
113            <div class="space-y-1">
114              <div class="font-medium text-sm">Draft</div>
115              <div class="text-xs text-green-600 dark:text-green-400">βœ“ Completed</div>
116            </div>
117          </StepperStep>
118          <StepperSeparator completed />
119          <StepperStep step={1}>
120            {#snippet icon()}
121              <User class="size-4" />
122            {/snippet}
123            <div class="space-y-1">
124              <div class="font-medium text-sm">Review</div>
125              <div class="text-xs text-blue-600 dark:text-blue-400">⟳ In Progress</div>
126            </div>
127          </StepperStep>
128          <StepperSeparator />
129          <StepperStep step={2}>
130            {#snippet icon()}
131              <CircleCheck class="size-4" />
132            {/snippet}
133            <div class="space-y-1">
134              <div class="font-medium text-sm">Publish</div>
135              <div class="text-xs text-muted-foreground">β—‹ Pending</div>
136            </div>
137          </StepperStep>
138        </StepperRoot>
139      </CardContent>
140    </Card>
141
142    <Card>
143      <CardHeader>
144        <CardTitle>With Time Estimates</CardTitle>
145      </CardHeader>
146      <CardContent>
147        <StepperRoot activeStep={0} variant="ghost">
148          <StepperStep step={0}>
149            {#snippet icon()}
150              <Briefcase class="size-4" />
151            {/snippet}
152            <div class="space-y-0.5">
153              <div class="font-medium text-sm">Interview</div>
154              <div class="text-xs text-muted-foreground">~30 minutes</div>
155            </div>
156          </StepperStep>
157          <StepperSeparator />
158          <StepperStep step={1}>
159            {#snippet icon()}
160              <GraduationCap class="size-4" />
161            {/snippet}
162            <div class="space-y-0.5">
163              <div class="font-medium text-sm">Assessment</div>
164              <div class="text-xs text-muted-foreground">~45 minutes</div>
165            </div>
166          </StepperStep>
167          <StepperSeparator />
168          <StepperStep step={2}>
169            {#snippet icon()}
170              <CircleCheck class="size-4" />
171            {/snippet}
172            <div class="space-y-0.5">
173              <div class="font-medium text-sm">Results</div>
174              <div class="text-xs text-muted-foreground">Instant</div>
175            </div>
176          </StepperStep>
177        </StepperRoot>
178      </CardContent>
179    </Card>
180  </div>
181
182
183
184