Tabs
The tabs
component is used to display a set of sections of content, each associated with a tab. Only one tab can be selected at a time.
Features
Behavior
By default, when navigating between tabs with a keyboard, the focused tab will be opened. This can be changed by setting the option behavior
to manual
.
Keyboard navigation
- ArrowLeft and ArrowRight keys can be used to navigate between tabs.
- Home and End keys can be used to navigate to the first and last tab respectively.
- Space and Enter keys can be used to select a tab.
- Tab key can be used to navigate to the next focusable element.
Example
Apples
Oranges
Grapes
There are thousands of apple varieties, each with its own unique taste and
texture. Apples come in a range of colors, including red, green, and yellow.
Sources
+page.svelte
<script lang="ts">
import Tabs from './Tabs.svelte'
import Tab from './Tab.svelte'
import TabPanel from './TabPanel.svelte'
</script>
<Tabs>
<svelte:fragment slot="tabs">
<Tab key="apples" icon="🍎">Apples</Tab>
<Tab key="oranges" icon="🍊">Oranges</Tab>
<Tab key="grapes" icon="🍇">Grapes</Tab>
</svelte:fragment>
<TabPanel key="apples">
There are thousands of apple varieties, each with its own unique taste and
texture. Apples come in a range of colors, including red, green, and yellow.
</TabPanel>
<TabPanel key="oranges">
They belong to the citrus family and have a refreshing, tangy flavor.
Oranges come in various varieties, such as navel oranges and Valencia
oranges.
</TabPanel>
<TabPanel key="grapes">
They grow in clusters on vines and come in different colors, including
green, red, and purple. Grapes are packed with antioxidants and are a good
source of vitamin K.
</TabPanel>
</Tabs>
Tab.svelte
<script lang="ts">
import type { Tabs } from 'louisette'
import { getContext } from 'svelte'
export let key: string
export let icon: string = ''
const { tabAttrs, active } = getContext<Tabs>('tabs')
</script>
<div
{...$tabAttrs(key)}
class="flex cursor-pointer select-none flex-wrap items-center gap-1 rounded-md p-2 transition-colors hover:bg-neutral-100 focus:outline-none focus-visible:ring focus-visible:ring-accent-500 focus-visible:ring-opacity-50 dark:hover:bg-neutral-700 max-md:justify-center"
class:is-active={$active === key}
>
{#if icon}
<span class="mr-1 text-sm" aria-hidden="true">{icon}</span>
{/if}
<slot />
</div>
<style lang="postcss">
.is-active {
@apply bg-neutral-300 dark:bg-neutral-700;
}
</style>
TabPanel.svelte
<script lang="ts">
import type { Tabs } from 'louisette'
import { getContext } from 'svelte'
export let key: string
const { panelAttrs, active } = getContext<Tabs>('tabs')
</script>
{#if $active === key}
<div {...$panelAttrs(key)}>
<slot />
</div>
{/if}
Tabs.svelte
<script lang="ts">
import { createTabs } from 'louisette'
import { setContext } from 'svelte'
const { listAttrs, ...tabsContext } = createTabs()
setContext('tabs', tabsContext)
</script>
<div
class="flex flex-col gap-2 overflow-clip rounded-lg border border-neutral-200 bg-white p-4 text-neutral-900 dark:border-neutral-600 dark:bg-neutral-800 dark:text-neutral-100"
>
<div {...$listAttrs} class="flex gap-2">
<slot name="tabs" />
</div>
<slot />
</div>