Skip to content

Before you use this component

  • Runtime dependencies: bits-ui ^2.0.0.
  • Requires client-side JavaScript to work.
Palette Neutral

Neutral palette · 4.9 KB ZIP File receipt View code

Preview

Fit to the available width. Previews taller than the maximum auto-height scroll inside the frame.

Use this component with your coding agent

Using the PageSugar MCP server, fetch component cmp_feature_tabs_001 version 1.0.0 with variant "neutral", first inspect its requirements and license status and confirm this project uses Svelte 5 and Tailwind CSS 4. Retrieve every manifest file, including binary assets and any manifest-only response files, preserving relative paths. Then integrate the source and follow its usage notes. Run project checks, review the browser result and report anything unverified. Do not substitute another version or invent missing files.

Code

Neutral palette, version 1.0.0. Artifact sha256-18ec61829023b8334d3d9be23df9b97b95562d770213afb31feb7d521d5e6280

Files (3)

This component is distributed as the complete file tree below. Copying one file is not enough; download the bundle to get every file.

parts/FeaturePanel.svelte · Svelte component · 1.2 KB

<script lang="ts">
	import type { FeatureTab } from '../types';

	interface Props {
		feature: FeatureTab;
		headingLevel: 3 | 4 | 5 | 6;
	}

	let { feature, headingLevel }: Props = $props();

	const heading = $derived(`h${headingLevel}`);
</script>

<div class="grid gap-8 md:grid-cols-2 md:gap-12">
	<div class="min-w-0">
		<svelte:element
			this={heading}
			class="text-2xl font-semibold tracking-tight text-balance break-words text-zinc-900"
		>
			{feature.title}
		</svelte:element>
		<p class="mt-4 text-base text-pretty break-words text-zinc-600">{feature.description}</p>
	</div>
	{#if feature.points && feature.points.length > 0}
		<ul class="min-w-0 space-y-3 rounded-2xl bg-zinc-50 p-6 text-sm text-zinc-700" role="list">
			{#each feature.points as point, index (index)}
				<li class="flex gap-3">
					<svg
						class="mt-0.5 size-4 shrink-0 text-zinc-900"
						viewBox="0 0 16 16"
						fill="none"
						aria-hidden="true"
					>
						<path
							d="M3.5 8.5l3 3 6-7"
							stroke="currentColor"
							stroke-width="1.75"
							stroke-linecap="round"
							stroke-linejoin="round"
						/>
					</svg>
					<span class="min-w-0 break-words">{point}</span>
				</li>
			{/each}
		</ul>
	{/if}
</div>

Usage

Supply feature tabs as data. The selected tab is local state; bind value or pass onValueChange to observe or control it. Requires the bits-ui package; no backend.

Suggested location: src/lib/components/feature-tabs-01

Required props: features, title

Example

Svelte
<!-- Illustrative content: replace example claims, prices and links before publishing. -->
<script lang="ts">
	import FeatureTabs from '$lib/components/feature-tabs-01/FeatureTabs.svelte';
	import type { FeatureTab } from '$lib/components/feature-tabs-01/types';

	const features: FeatureTab[] = [
		{ value: 'plan', label: 'Plan', title: 'Plan work in one place', description: 'Collect tasks, owners and dates on a shared board.', points: ['Shared boards', 'Due dates'] },
		{ value: 'track', label: 'Track', title: 'See progress at a glance', description: 'Status updates roll up into a weekly summary.' }
	];

	let selected = $state('plan');
</script>

<FeatureTabs title="How it works" {features} bind:value={selected} />

Limitations

  • Install bits-ui (npm install bits-ui@^2) before using the component.
  • Panel content is plain text; edit FeaturePanel.svelte to add media or rich content.
  • Every feature value must be unique; it is used as the tab key.
  • Tab switching needs JavaScript; before hydration only the initially selected panel is visible.

Adding the complete file set #

Install the declared Bits UI dependency and copy all three files into src/lib/components/feature-tabs-01/, keeping these relative paths:

Plain text
FeatureTabs.svelte
parts/FeaturePanel.svelte
types.ts

Copying the entry component alone is not enough. The quick-start example shows how to import FeatureTab and bind the selected value. Example planning and reporting features describe a fictional product.

Extending a panel #

For richer panel content, edit parts/FeaturePanel.svelte and extend FeatureTab in types.ts together. Keep each tab value unique and check that headings fit the surrounding page. For manual activation, add activationMode="manual" to Tabs.Root; verify keyboard behaviour after the change.

Customization

Change tabs through the features prop, edit the panel layout in parts/FeaturePanel.svelte, and edit Tailwind classes for colours and spacing. No colour tokens are declared.

  • Content: add, remove or reorder entries in features; keep each value unique and stable.
  • Panel layout: edit parts/FeaturePanel.svelte to add an image, link or different grid; extend FeatureTab in types.ts to match.
  • Active tab style: change the data-[state=active]: border and text utilities on Tabs.Trigger.
  • Colours: replace the zinc text, border and outline utilities together and keep text at 4.5:1 contrast.
  • Activation: Bits UI activates tabs on focus by default; add activationMode="manual" to Tabs.Root if panels are expensive to render.
  • Headings: set headingLevel to fit the page outline; panel titles use the next level.

Props and content inputs

NameTypeRequiredDefaultDescription
featuresFeatureTab[]YesNoneTabs in display order: { value, label, title, description, points? }. value must be unique.
titlestringYesNoneSection heading text; also labels the tab list.
descriptionstringNoNoneOptional introductory paragraph under the heading.
headingLevel2 | 3 | 4 | 5No2Level of the section heading; panel titles use the next level down.
valuestringNofeatures[0].valueSelected tab value. Bindable with bind:value.
onValueChange(value: string) => voidNoNoneCalled with the new value whenever the user selects a different tab. Local UI callback only.

Dependencies and services

PackageRangeResolved at build timePurpose
bits-ui^2.0.02.19.2Headless Tabs primitive providing tab/tablist/tabpanel roles, roving focus and arrow-key navigation.

Install with (shown for reference, run it yourself):

npm install bits-ui@^2.0.0

Integration boundaries

  • Integration level: local-interaction.
  • Requires client-side JavaScript to be interactive.
  • Server-side rendering: supported.

Accessibility

  • Implements the WAI-ARIA tabs pattern through Bits UI: tablist, tab and tabpanel roles with aria-selected, aria-controls and aria-labelledby.
  • Arrow keys move between tabs (looping), Home and End jump to the first and last tab, and only the selected tab is in Tab order.
  • The tab list is labelled by the section heading; the selected tab is indicated by text colour and an underline, not colour alone.
  • Panels are focusable so keyboard users can reach panel content directly after the tab list; focus is shown with a visible outline.
  • Tab and panel IDs, aria-controls, aria-labelledby and the roving tabindex are set explicitly from $props.id() and the selected value, so server-rendered markup is complete before hydration and multiple instances never collide.

Known limitations

  • On narrow screens tabs scroll horizontally; there is no visible scroll affordance beyond the clipped last tab.

License

Declared source license: MIT.

Default license approval is pending. See the license status before adopting the source.

Version history

Only the current release is available. Keep downloaded source and its receipt if you need to use it again later.

  • 1.0.0 Published current · selected · 16 September 2026

Search components

Describe a section or control, such as “FAQ accordion” or “newsletter signup”.