# Scroll Area

Themed scroll container with vertical or horizontal overflow.

- Package: `@mielui/svelte`
- Component version: `1.0.1`
- Depends on Mielui components: _internal/utils
- Shared utilities: utils.cn

## Install

~~~~sh
pnpm dlx @mielui/svelte add scroll-area
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### ScrollArea

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| orientation | "vertical" \| "horizontal" \| "both" \| undefined | 'vertical' | No | No | Scroll direction. |
| showCues | boolean \| undefined | true | No | No | Fades an edge that has more content. |
| blur | boolean \| undefined | true | No | No | Blurs content as it passes under a faded edge. |
| children | Snippet<[]> \| undefined | - | No | No | Content rendered inside. |
| element | HTMLDivElement \| undefined | - | No | Yes | Bindable reference to the DOM element. |
| class | string \| undefined | - | No | No | Classes added to the element. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Public types

~~~~ts
import type { DefaultProps } from '@mielui/svelte/utils';
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
import ScrollArea from './scroll-area.svelte';

export type ScrollAreaProps = {
    /** Scroll direction. */
    orientation?: 'vertical' | 'horizontal' | 'both';
    /** Fades an edge that has more content. */
    showCues?: boolean;
    /** Blurs content as it passes under a faded edge. */
    blur?: boolean;
    /** Content rendered inside. */
    children?: Snippet;
    /** Bindable reference to the DOM element. */
    element?: HTMLDivElement;
} & DefaultProps &
    Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'class'>;

export { ScrollArea };
export default ScrollArea;
~~~~

## Examples

### Blur

~~~~svelte
<script lang="ts">
    import { ScrollArea } from '@mielui/svelte/components/scroll-area';

    const commits = [
        {
            hash: '9f2c1ab',
            message: 'Tighten the panel elevation ramp'
        },
        {
            hash: '4d80e73',
            message: 'Drop the unused motion fallback'
        },
        {
            hash: 'b17aa90',
            message: 'Document the density scale'
        },
        {
            hash: '02f5c6e',
            message: 'Fix toast stacking on mobile'
        },
        {
            hash: 'ac9013d',
            message: 'Add a reduced-motion snapshot'
        },
        {
            hash: '76be24f',
            message: 'Rename the radius tokens'
        },
        {
            hash: 'e3c8a15',
            message: 'Guard the popover outside click'
        },
        {
            hash: '5a10f9b',
            message: 'Split the theme export helpers'
        },
        {
            hash: 'd42e607',
            message: 'Cache the syntax highlighter'
        },
        {
            hash: '81fb3c2',
            message: 'Correct the badge outline width'
        },
        {
            hash: '3c67d48',
            message: 'Trim the changelog compiler'
        },
        {
            hash: 'f905b1e',
            message: 'Restore the focus ring on Safari'
        }
    ];
</script>

{#snippet commitList()}
    <div class="flex flex-col p-2">
        {#each commits as commit (commit.hash)}
            <div class="flex items-baseline gap-3 rounded-[var(--radius-md)] px-3 py-2 text-sm">
                <span class="font-mono text-xs text-foreground-muted tabular-nums">
                    {commit.hash}
                </span>
                <span class="truncate text-foreground">{commit.message}</span>
            </div>
        {/each}
    </div>
{/snippet}

<div class="flex flex-wrap items-start justify-center gap-6 p-10">
    <div class="flex flex-col gap-2">
        <span class="px-1 text-xs font-medium text-foreground-muted">Blurred cue</span>
        <ScrollArea
            tabindex={0}
            role="region"
            aria-label="Commits with a blurred edge cue"
            class="h-56 w-72 rounded-[var(--radius-xl)] border border-border bg-card shadow-[var(--elevation-1)]"
        >
            {@render commitList()}
        </ScrollArea>
    </div>

    <div class="flex flex-col gap-2">
        <span class="px-1 text-xs font-medium text-foreground-muted">Fade only</span>
        <ScrollArea
            blur={false}
            tabindex={0}
            role="region"
            aria-label="Commits without a blurred edge cue"
            class="h-56 w-72 rounded-[var(--radius-xl)] border border-border bg-card shadow-[var(--elevation-1)]"
        >
            {@render commitList()}
        </ScrollArea>
    </div>
</div>
~~~~

### Both

~~~~svelte
<script lang="ts">
    import { ScrollArea } from '@mielui/svelte/components/scroll-area';

    const lines = [
        '09:00:02 Cloning github.com/acme/storefront at commit 4d11ba0',
        '09:00:04 Restored build cache from the previous deployment',
        '09:00:09 Installing dependencies with pnpm install --frozen-lockfile',
        '09:00:21 Running pnpm run build in apps/storefront',
        '09:00:38 Compiled 214 modules for the client bundle',
        '09:00:44 Compiled 96 modules for the server bundle',
        '09:00:47 Prerendered 38 static routes',
        '09:00:52 Uploading build output to the edge network',
        '09:00:58 Assigned the production domain storefront.acme.com',
        '09:01:01 Deployment completed in 59 seconds',
        '09:01:03 Health check passed in 3 regions',
        '09:01:04 Notified the #deploys channel'
    ];
</script>

<ScrollArea
    orientation="both"
    tabindex={0}
    role="region"
    aria-label="Deploy log"
    class="h-56 w-72 rounded-[var(--radius-xl)] border border-border bg-card"
>
    <div
        class="flex w-max flex-col gap-1.5 p-3 font-mono text-xs whitespace-nowrap text-foreground-muted"
    >
        {#each lines as line (line)}
            <span>{line}</span>
        {/each}
    </div>
</ScrollArea>
~~~~

### Grouped List

~~~~svelte
<script lang="ts">
    import { ScrollArea } from '@mielui/svelte/components/scroll-area';

    const groups = [
        {
            date: 'Today',
            chats: [
                'Svelte 5 runes migration',
                'Designing the studio preset',
                'Tailwind v4 token setup',
                'Pagination active state'
            ]
        },
        {
            date: 'Yesterday',
            chats: [
                'Figma plugin ideas',
                'Vercel deploy hook',
                'Refactor command palette',
                'Hover card a11y'
            ]
        },
        {
            date: 'Previous 7 days',
            chats: [
                'Toast queue logic',
                'Color picker math',
                'Button loading states',
                'Dialog scroll behavior',
                'Badge variant system',
                'Breadcrumb navigation',
                'Dropdown menu icons',
                'Alert dialog focus trap'
            ]
        }
    ];

    let active = $state('Svelte 5 runes migration');
</script>

<div class="flex w-full min-w-0 items-center justify-center p-2 sm:p-6">
    <ScrollArea
        aria-label="Recent chats"
        class="h-72 w-full max-w-72 rounded-[var(--radius-xl)] border border-border bg-card shadow-[var(--elevation-1)]"
    >
        <div class="flex flex-col p-2">
            {#each groups as group (group.date)}
                <div class="px-2 py-2 pt-3 text-xs font-medium text-foreground-muted">
                    {group.date}
                </div>
                {#each group.chats as chat (chat)}
                    <button
                        type="button"
                        aria-pressed={active === chat}
                        onclick={() => {
                            active = chat;
                        }}
                        class={[
                            'w-full truncate rounded-[var(--radius-md)] px-3 py-2 text-start text-sm transition-colors [transition-duration:var(--motion-duration-hover)] focus-visible:outline-none focus-visible:shadow-[var(--focus-ring)] motion-reduce:transition-none',
                            active === chat
                                ? 'bg-[var(--color-wash)] font-medium text-foreground'
                                : 'text-foreground-muted hover:bg-[var(--color-wash)] hover:text-foreground'
                        ]}
                    >
                        {chat}
                    </button>
                {/each}
            {/each}
        </div>
    </ScrollArea>
</div>
~~~~

### Horizontal

~~~~svelte
<script lang="ts">
    import { ScrollArea } from '@mielui/svelte/components/scroll-area';

    const tabs = [
        'Overview',
        'Activity',
        'Settings',
        'Members',
        'Billing',
        'Integrations',
        'Webhooks',
        'Security',
        'Audit log',
        'Danger zone'
    ];
</script>

<div class="flex items-center justify-center p-10">
    <ScrollArea
        orientation="horizontal"
        tabindex={0}
        role="region"
        aria-label="Project sections"
        class="w-72 rounded-[var(--radius-control)] border border-border bg-card p-1.5 shadow-[var(--elevation-1)]"
    >
        <div class="flex gap-2">
            {#each tabs as tab (tab)}
                <span
                    class="whitespace-nowrap rounded-[var(--radius-control)] bg-secondary px-3 py-1 text-sm text-foreground"
                >
                    {tab}
                </span>
            {/each}
        </div>
    </ScrollArea>
</div>
~~~~

For the rendered reference, visit [/docs/components/scroll-area](/docs/components/scroll-area).
