Account
Make changes to your account here. Click save when you're done.
Password
Change your password here. After saving, you'll be logged out.
<script lang="ts">
import * as Tabs from "$lib/components/ui/tabs/index.js";
import * as Card from "$lib/components/ui/card/index.js";
import { Button } from "$lib/components/ui/button/index.js";
import { Input } from "$lib/components/ui/input/index.js";
import { Label } from "$lib/components/ui/label/index.js";
</script>
<div class="-mb-4 flex w-full max-w-sm flex-col gap-6">
<Tabs.Root value="account">
<Tabs.List>
<Tabs.Trigger value="account">Account</Tabs.Trigger>
<Tabs.Trigger value="password">Password</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="account">
<Card.Root>
<Card.Header>
<Card.Title>Account</Card.Title>
<Card.Description>
Make changes to your account here. Click save when you're done.
</Card.Description>
</Card.Header>
<Card.Content class="grid gap-6">
<div class="grid gap-3">
<Label for="tabs-demo-name">Name</Label>
<Input id="tabs-demo-name" value="Pedro Duarte" />
</div>
<div class="grid gap-3">
<Label for="tabs-demo-username">Username</Label>
<Input id="tabs-demo-username" value="@peduarte" />
</div>
</Card.Content>
<Card.Footer>
<Button>Save changes</Button>
</Card.Footer>
</Card.Root>
</Tabs.Content>
<Tabs.Content value="password">
<Card.Root>
<Card.Header>
<Card.Title>Password</Card.Title>
<Card.Description>
Change your password here. After saving, you'll be logged out.
</Card.Description>
</Card.Header>
<Card.Content class="grid gap-6">
<div class="grid gap-3">
<Label for="tabs-demo-current">Current password</Label>
<Input id="tabs-demo-current" type="password" />
</div>
<div class="grid gap-3">
<Label for="tabs-demo-new">New password</Label>
<Input id="tabs-demo-new" type="password" />
</div>
</Card.Content>
<Card.Footer>
<Button>Save password</Button>
</Card.Footer>
</Card.Root>
</Tabs.Content>
</Tabs.Root>
</div> Installation
pnpm dlx shadcn-svelte@latest add tabs Install bits-ui:
pnpm add bits-ui -D Copy and paste the following code into your project.
import Root from './tabs.svelte';
import Content from './tabs-content.svelte';
import List, { tabsListVariants, type TabsListVariant } from './tabs-list.svelte';
import Trigger from './tabs-trigger.svelte';
export {
Root,
Content,
List,
Trigger,
tabsListVariants,
type TabsListVariant,
//
Root as Tabs,
Content as TabsContent,
List as TabsList,
Trigger as TabsTrigger
};
<script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$UTILS$.js';
let {
ref = $bindable(null),
class: className,
...restProps
}: TabsPrimitive.ContentProps = $props();
</script>
<TabsPrimitive.Content
bind:ref
data-slot="tabs-content"
class={cn(
'flex-1 border border-zinc-800 bg-background p-4 text-sm text-zinc-300 outline-none',
className
)}
{...restProps}
/>
<script lang="ts" module>
import { tv, type VariantProps } from 'tailwind-variants';
export const tabsListVariants = tv({
base: 'group/tabs-list inline-flex w-fit items-center justify-center border border-zinc-800 bg-background p-1 font-mono text-xs text-zinc-500 group-data-horizontal/tabs:h-10 group-data-[orientation=vertical]/tabs:h-fit group-data-[orientation=vertical]/tabs:flex-col',
variants: {
variant: {
default: 'cn-tabs-list-variant-default rounded-full',
line: 'cn-tabs-list-variant-line gap-1 rounded-none bg-transparent'
}
},
defaultVariants: {
variant: 'default'
}
});
export type TabsListVariant = VariantProps<typeof tabsListVariants>['variant'];
</script>
<script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$UTILS$.js';
let {
ref = $bindable(null),
variant = 'default',
class: className,
...restProps
}: TabsPrimitive.ListProps & {
variant?: TabsListVariant;
} = $props();
</script>
<TabsPrimitive.List
bind:ref
data-slot="tabs-list"
data-variant={variant}
class={cn(tabsListVariants({ variant }), className)}
{...restProps}
/>
<script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$UTILS$.js';
let {
ref = $bindable(null),
class: className,
...restProps
}: TabsPrimitive.TriggerProps = $props();
</script>
<TabsPrimitive.Trigger
bind:ref
data-slot="tabs-trigger"
class={cn(
"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-2 rounded-full border border-transparent px-4 py-1.5 font-mono text-xs font-semibold tracking-[0.12em] whitespace-nowrap text-zinc-500 uppercase transition-all hover:text-white group-data-vertical/tabs:px-4 group-data-vertical/tabs:py-2 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5 focus-visible:border-zinc-300 focus-visible:ring-2 focus-visible:ring-zinc-300/30 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-3.5",
'group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent',
'data-active:border-[#d0e891] data-active:bg-[#b9d765] data-active:text-[#101207] dark:data-active:border-[#d0e891] dark:data-active:bg-[#b9d765] dark:data-active:text-[#101207]',
'after:absolute after:bg-[#d0e891] after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-px group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-px group-data-[variant=line]/tabs-list:data-active:after:opacity-100',
className
)}
{...restProps}
/>
<script lang="ts">
import { Tabs as TabsPrimitive } from 'bits-ui';
import { cn } from '$UTILS$.js';
let {
ref = $bindable(null),
value = $bindable(''),
class: className,
...restProps
}: TabsPrimitive.RootProps = $props();
</script>
<TabsPrimitive.Root
bind:ref
bind:value
data-slot="tabs"
class={cn(
'group/tabs flex gap-2 text-zinc-100 data-[orientation=horizontal]:flex-col',
className
)}
{...restProps}
/>
Usage
<script lang="ts">
import * as Tabs from '$lib/components/ui/tabs/index.js';
</script> <Tabs.Root value="account" class="w-[400px]">
<Tabs.List>
<Tabs.Trigger value="account">Account</Tabs.Trigger>
<Tabs.Trigger value="password">Password</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="account">Make changes to your account here.</Tabs.Content>
<Tabs.Content value="password">Change your password here.</Tabs.Content>
</Tabs.Root>