컴포넌트

Scroll Area

지정한 영역 안에서 콘텐츠를 스크롤합니다.

설치

pnpm dlx ply-ui add scroll-area

공통 설치 설정을 먼저 적용합니다.

사용법

Root에 높이를 지정하고 Viewport 안에 내용을 넣습니다.

Scrollbar 안에 Thumb를 넣고, 스크롤 영역의 이름을 aria-label로 설명합니다.

구성

구성 요소역할
Root스크롤 영역 전체를 묶습니다.
Viewport실제로 스크롤되는 내용의 창입니다.
Content스크롤할 내용을 담습니다.
Scrollbar세로 또는 가로 스크롤바입니다.
Thumb스크롤 위치를 표시하고 조작하는 손잡이입니다.

구현 코드

components/ui/scroll-area.tsx
scroll-area.tsx
"use client";

import type { ComponentProps } from "react";
import { ScrollArea as Primitive } from "@base-ui/react/scroll-area";
import { withClassName } from "../../lib/cx";
import "./scroll-area.css";

// 동작과 접근성은 Base UI가 담당합니다. 이 파일은 스타일 연결만 담당합니다.
function ScrollAreaRoot({
  className,
  ...props
}: ComponentProps<typeof Primitive.Root>) {
  return (
    <Primitive.Root
      {...props}
      className={withClassName("rbx-scroll-area", className)}
    />
  );
}

function ScrollAreaViewport({
  className,
  ...props
}: ComponentProps<typeof Primitive.Viewport>) {
  return (
    <Primitive.Viewport
      {...props}
      className={withClassName("rbx-scroll-viewport", className)}
    />
  );
}

function ScrollAreaScrollbar({
  className,
  ...props
}: ComponentProps<typeof Primitive.Scrollbar>) {
  return (
    <Primitive.Scrollbar
      {...props}
      className={withClassName("rbx-scrollbar", className)}
    />
  );
}

function ScrollAreaThumb({
  className,
  ...props
}: ComponentProps<typeof Primitive.Thumb>) {
  return (
    <Primitive.Thumb
      {...props}
      className={withClassName("rbx-scroll-thumb", className)}
    />
  );
}

// Root/Portal 등 스타일 없는 파트와 제네릭 API는 원본을 그대로 보존합니다.
export const ScrollArea = {
  ...Primitive,
  Root: ScrollAreaRoot,
  Viewport: ScrollAreaViewport,
  Scrollbar: ScrollAreaScrollbar,
  Thumb: ScrollAreaThumb,
};
components/ui/scroll-area.css
scroll-area.css
/* ScrollArea: 공통 구조는 theme.css, 컴포넌트 전용 조정은 아래에 작성합니다. */
.rbx-scroll-area {
  position: relative;
  overflow: hidden;
}
.rbx-scroll-viewport {
  width: 100%;
  height: 100%;
}
.rbx-scrollbar {
  display: flex;
  width: 6px;
  padding: 1px;
  margin: 4px;
  opacity: 0;
  transition: opacity var(--rbx-motion-duration-feedback)
    var(--rbx-motion-ease-enter);
}
.rbx-scrollbar[data-hovering],
.rbx-scrollbar[data-scrolling] {
  opacity: 1;
}
.rbx-scroll-thumb {
  flex: 1;
  background: var(--rbx-color-content-muted);
  border-radius: 99px;
}

목차