For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/en/llms-full.txt, and this page is available as Markdown at https://ifhover.github.io/leaf-ui/en/components/scrollbar.md.

Scrollbar

Browse long or wide content inside a region.

Basic usage

Scrollbars fade in when the pointer enters the region and fade out when it leaves, without taking up content space. Wheel, touch and keyboard scrolling retain native behavior.

Project activity 1
Project activity 2
Project activity 3
Project activity 4
Project activity 5
Project activity 6
Project activity 7
Project activity 8
Project activity 9
Project activity 10
Project activity 11
Project activity 12
basic.tsx
import { Scrollbar } from '@ifhover/leaf-ui';

export function ScrollbarBasic() {
  return (
    <Scrollbar height={200} aria-label={'Project activity'}>
      {Array.from({ length: 12 }, (_, index) => (
        <div key={String(index)} style={{ padding: '12px 20px' }}>
          {'Project activity'} {index + 1}
        </div>
      ))}
    </Scrollbar>
  );
}

Horizontal and always visible

orientation controls the scrolling axes. Use scrollbar="always" to keep bars visible, or hidden to hide them without disabling scrolling. Drag a thumb or click its track to move through the content.

Project 1
Project 2
Project 3
Project 4
Project 5
Project 6
basic.tsx
import { Scrollbar } from '@ifhover/leaf-ui';

export function ScrollbarHorizontal() {
  return (
    <Scrollbar
      orientation="horizontal"
      scrollbar="always"
      aria-label={'Project board'}
    >
      <div style={{ display: 'flex', width: 'max-content', gap: 16, padding: '12px 12px 24px' }}>
        {Array.from({ length: 6 }, (_, index) => (
          <div
            key={String(index)}
            style={{
              width: 180,
              padding: 24,
              borderRadius: 'var(--leaf-radius)',
              background: 'var(--leaf-color-surface-muted)',
            }}
          >
            {'Project'} {index + 1}
          </div>
        ))}
      </div>
    </Scrollbar>
  );
}

Dynamic content and scroll control

Thumbs update when content or container sizes change. The forwarded ref points to the scrolling viewport: call scrollTo, read scrollTop, or use it with BackTop. At a scroll boundary, or when content fits, the wheel continues scrolling the page.

Item 1
Item 2
Item 3
basic.tsx
import { Button, Flex, Scrollbar } from '@ifhover/leaf-ui';

import { useRef, useState } from 'react';

export function ScrollbarDynamic() {
  const viewport = useRef<HTMLDivElement>(null);
  const [count, setCount] = useState(3);
  return (
    <Flex direction="column" gap="md">
      <Flex gap="sm" wrap>
        <Button variant="outline" onClick={() => setCount((previous) => previous + 3)}>
          {'Add items'}
        </Button>
        <Button
          variant="soft"
          onClick={() => viewport.current?.scrollTo({ top: 0, behavior: 'smooth' })}
        >
          {'Back to top'}
        </Button>
      </Flex>
      <Scrollbar ref={viewport} maxHeight={200} aria-label={'Dynamic list'}>
        {Array.from({ length: count }, (_, index) => (
          <div key={String(index)} style={{ padding: '12px 20px' }}>
            {'Item'} {index + 1}
          </div>
        ))}
      </Scrollbar>
    </Flex>
  );
}

Scrollbar API

import type { ScrollbarProps } from '@ifhover/leaf-ui';
PropertyTypeDefaultDescription
heightCSSProperties['height']—Viewport height.
maxHeightCSSProperties['maxHeight']—Maximum height; unconstrained content determines its own height.
orientation'vertical' | 'horizontal' | 'both''both'Scrolling axes.
scrollbar'auto' | 'always' | 'hidden''auto'Scrollbar visibility.
viewportClassNamestring—Class for the scrolling viewport.
viewportStyleCSSProperties—Styles for the scrolling viewport.
contentClassNamestring—Class for the content container.
contentStyleCSSProperties—Styles for the content container.
verticalOffsetnumber0Top inset for the vertical track, useful with sticky headers.

style and className apply to the outer wrapper. id, role, tabIndex, region names and onScroll apply to the scrolling viewport. Provide aria-label or aria-labelledby to name it. Focus a thumb with Tab and use arrow keys, PageUp / PageDown or Home / End.

ScrollArea uses the same scrollbar implementation and defaults to vertical scrolling. Existing usage remains supported.