Tabbed section layout: tabs on desktop, nav cards on phones.

One real route per tab, under a layout that renders the section. The live demo below is the code on this page: on desktop it opens the first tab, on phones it lists the tabs as cards.

Open the demo section

Usage

section/+layout.svelte
<script lang="ts">
	import { resolve } from "$app/paths";

	import TabSection from "@orochibraru/ui/blocks/tab-section";

	import { tabs } from "./tabs.js";

	const { children } = $props();
</script>

<TabSection
	title="Section"
	indexHref={resolve("/section")}
	backHref={resolve("/[group]/[slug]", {
		group: "blocks",
		slug: "tab-section",
	})}
	{tabs}
>
	{@render children()}
</TabSection>
section/+page.svelte
<script lang="ts">
	import NavCards from "@orochibraru/ui/blocks/nav-cards";

	import { tabs } from "./tabs.js";
</script>

<NavCards {tabs} />
section/appearance/+page.svelte
<script lang="ts">
	import ThemePicker from "@orochibraru/ui/blocks/theme-picker";
</script>

<ThemePicker />
section/profile/+page.svelte
<script lang="ts">
	import * as Field from "@orochibraru/ui/field";
	import { Input } from "@orochibraru/ui/input";
</script>

<Field.Group>
	<Field.Field>
		<Field.Label for="name">Name</Field.Label>
		<Input id="name" value="Alex" />
	</Field.Field>
	<Field.Field>
		<Field.Label for="profile-email">Email</Field.Label>
		<Input id="profile-email" type="email" value="alex@example.com" />
	</Field.Field>
</Field.Group>
section/tabs.ts
import { resolve } from "$app/paths";
import PaletteIcon from "@lucide/svelte/icons/palette";
import UserRoundIcon from "@lucide/svelte/icons/user-round";

import type { SectionTab } from "@orochibraru/ui/blocks/nav-cards";

export const tabs: SectionTab[] = [
	{
		href: resolve("/section/profile"),
		label: "Profile",
		description: "Your name and the email you sign in with.",
		icon: UserRoundIcon,
	},
	{
		href: resolve("/section/appearance"),
		label: "Appearance",
		description: "Light, dark, or whatever the device says.",
		icon: PaletteIcon,
	},
];