<script lang="ts">
import ArrowRightIcon from "phosphor-svelte/lib/ArrowRightIcon";
import { Button } from "kumo-svelte/components/button";
import * as LayerCard from "kumo-svelte/components/layer-card";
</script>
<LayerCard.Root layered>
<LayerCard.Secondary class="flex items-center justify-between">
<div>Next Steps</div>
<Button variant="ghost" size="sm" shape="square" aria-label="Go to next steps">
<ArrowRightIcon size={16} />
</Button>
</LayerCard.Secondary>
<LayerCard.Primary>Get started with Kumo</LayerCard.Primary>
</LayerCard.Root>
Import
import * as LayerCard from "kumo-svelte/components/layer-card"; Usage
<script lang="ts">
import * as LayerCard from "kumo-svelte/components/layer-card";
</script>
<LayerCard.Root layered class="w-[250px]">
<LayerCard.Secondary>Documentation</LayerCard.Secondary>
<LayerCard.Primary>Learn how to use Kumo components</LayerCard.Primary>
</LayerCard.Root> LayerCard also supports a simple surface-style mode for cases where you do not need a secondary header row. In those cases, render content directly inside LayerCard and omit the layered prop.
<LayerCard.Root class="w-[250px] p-4">
Learn how to use Kumo components
</LayerCard.Root> Examples
Basic Card
Quick start guide for new users
<script lang="ts">
import * as LayerCard from "kumo-svelte/components/layer-card";
</script>
<LayerCard.Root layered class="w-[250px]">
<LayerCard.Secondary>Getting Started</LayerCard.Secondary>
<LayerCard.Primary>
<p class="text-sm text-kumo-subtle">Quick start guide for new users</p>
</LayerCard.Primary>
</LayerCard.Root>
Surface-style Card
For simple card containers, render content directly inside LayerCard without LayerCard.Primary.
Quick start guide for new users
<script lang="ts">
import * as LayerCard from "kumo-svelte/components/layer-card";
</script>
<LayerCard.Root class="w-[250px] p-4">
<p class="text-sm text-kumo-subtle">Quick start guide for new users</p>
</LayerCard.Root>
Multiple Cards
Browse all components
View code examples
<script lang="ts">
import * as LayerCard from "kumo-svelte/components/layer-card";
</script>
<div class="flex flex-wrap gap-4">
<LayerCard.Root layered class="w-[200px]">
<LayerCard.Secondary>Components</LayerCard.Secondary>
<LayerCard.Primary>
<p class="text-sm">Browse all components</p>
</LayerCard.Primary>
</LayerCard.Root>
<LayerCard.Root layered class="w-[200px]">
<LayerCard.Secondary>Examples</LayerCard.Secondary>
<LayerCard.Primary>
<p class="text-sm">View code examples</p>
</LayerCard.Primary>
</LayerCard.Root>
</div>
Filter Toolbar with Small Tabs
Combine Tabs size="sm" with Input size="sm" inside a LayerCard for compact filter toolbars. Both share the same 26px height.
<script lang="ts">
import { Badge } from "kumo-svelte/components/badge";
import { Input } from "kumo-svelte/components/input";
import * as LayerCard from "kumo-svelte/components/layer-card";
import * as Tabs from "kumo-svelte/components/tabs";
const origins = [
{ origin: "challenges.cloudflare.com", s2xx: 1, s4xx: 0, duration: "95.4ms" },
{ origin: "Unknown", s2xx: 19, s4xx: 7, duration: "463.7ms" },
{ origin: "api.example.com", s2xx: 42, s4xx: 3, duration: "128.1ms" },
];
type StatusFilter = "all" | "2xx" | "3xx" | "4xx" | "5xx";
let filter = $state<StatusFilter>("all");
let search = $state("");
let filtered = $derived(
origins.filter((origin) => {
if (filter === "2xx" && origin.s2xx === 0) return false;
if (filter === "4xx" && origin.s4xx === 0) return false;
if (search && !origin.origin.toLowerCase().includes(search.toLowerCase())) return false;
return true;
}),
);
</script>
<LayerCard.Root layered class="w-full max-w-[540px]">
<LayerCard.Secondary>Subrequests</LayerCard.Secondary>
<LayerCard.Primary>
<div class="mb-2 flex items-center gap-3">
<Input
size="sm"
placeholder="Filter origins…"
aria-label="Filter origins"
bind:value={search}
class="min-w-0 flex-1"
/>
<Tabs.Root
variant="segmented"
size="sm"
class="shrink-0"
value={filter}
onValueChange={(value) => {
filter = value as StatusFilter;
}}
>
<Tabs.List>
<Tabs.Trigger value="all">All</Tabs.Trigger>
<Tabs.Trigger value="2xx">2xx</Tabs.Trigger>
<Tabs.Trigger value="3xx">3xx</Tabs.Trigger>
<Tabs.Trigger value="4xx">4xx</Tabs.Trigger>
<Tabs.Trigger value="5xx">5xx</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
</div>
<div class="-mx-1 text-sm">
<div class="grid grid-cols-[1fr_auto_auto] gap-x-4 border-b border-kumo-fill px-1 pb-2 text-xs font-medium text-kumo-subtle">
<span>Origin</span>
<span class="w-28 text-right">Requests</span>
<span class="w-20 text-right">Duration</span>
</div>
{#each filtered as row, index (row.origin)}
<div
class="grid grid-cols-[1fr_auto_auto] items-center gap-x-4 px-1 py-2.5"
class:border-b={index < filtered.length - 1}
class:border-kumo-hairline={index < filtered.length - 1}
>
<span class="truncate font-medium text-kumo-default">{row.origin}</span>
<div class="flex w-28 items-center justify-end gap-1.5">
{#if row.s2xx > 0}<Badge variant="success">2xx {row.s2xx}</Badge>{/if}
{#if row.s4xx > 0}<Badge variant="error">4xx {row.s4xx}</Badge>{/if}
</div>
<span class="w-20 text-right text-kumo-subtle">{row.duration}</span>
</div>
{/each}
</div>
<div class="-mx-1 border-t border-kumo-fill pt-2 text-xs text-kumo-subtle">
Showing {filtered.length} of {origins.length}
</div>
</LayerCard.Primary>
</LayerCard.Root>
Test IDs
LayerCard.Primary and LayerCard.Secondary accept all standard HTML attributes, including data-testid for testing.
Quick start guide for new users
<script lang="ts">
import * as LayerCard from "kumo-svelte/components/layer-card";
</script>
<LayerCard.Root layered class="w-[250px]">
<LayerCard.Secondary data-testid="card-header">Getting Started</LayerCard.Secondary>
<LayerCard.Primary data-testid="card-body">
<p class="text-sm text-kumo-subtle">Quick start guide for new users</p>
</LayerCard.Primary>
</LayerCard.Root>
API Reference
LayerCard
| Prop | Type | Default |
|---|---|---|
| as | keyof HTMLElementTagNameMap | "div" |
| children | Snippet | — |
| class | string | — |
| layered | boolean | false |
LayerCard.Primary
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
| class | string | — |
LayerCard.Secondary
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
| class | string | — |
Layered Cards
Use layered on the root when composing the primary and secondary regions.