Skip to content

Early previewhamur is not on npm yet. The components are being built in the open, follow along on GitHub.

LayoutReact

Scroll Area

A native scroll container with custom scrollbars.

Rendered by React 19.3.1

import { ScrollArea } from '@hamur/react/scroll-area'

const paragraphs = [
  'Vernacular architecture is building done outside any academic tradition, and without professional guidance.',
  'It is not a particular movement or style, but a broad category of building types, methods of construction and places, both historical and extant.',
  'It usually serves immediate, local needs, is constrained by the materials of its region and reflects local traditions and practices.',
  'More recently it has been examined by designers and the building industry in an effort to be more energy conscious.',
]

export default function ScrollAreaExample() {
  return (
    <ScrollArea.Root className="scroll-area">
      <ScrollArea.Viewport className="scroll-viewport">
        <ScrollArea.Content className="scroll-content">
          {paragraphs.map((text) => (
            <p key={text}>{text}</p>
          ))}
        </ScrollArea.Content>
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar className="scrollbar">
        <ScrollArea.Thumb className="scroll-thumb" />
      </ScrollArea.Scrollbar>
    </ScrollArea.Root>
  )
}
312Tests passing in React · 0 failing
10.3 KiBSize
Not measured yetMemory
Not measured yetSpeed
productdevbook and 18 upstream authors7 commits · last

Installation

npm i @hamur/react

Not on npm yet. The package goes out under the chosen name.

Anatomy

Import the component and assemble its parts:

<ScrollArea.Root>
  <ScrollArea.Viewport>
    <ScrollArea.Content />
  </ScrollArea.Viewport>
  <ScrollArea.Scrollbar>
    <ScrollArea.Thumb />
  </ScrollArea.Scrollbar>
</ScrollArea.Root>

// Not in this example: ScrollArea.Corner

Examples

Both

Two scrollbars, with Corner where they meet.

ScrollAreaBoth.tsx
import { ScrollArea } from '@hamur/react/scroll-area'

export default function ScrollAreaBothExample() {
  return (
    <ScrollArea.Root className="scroll-area">
      <ScrollArea.Viewport className="scroll-viewport">
        <ScrollArea.Content>
          <ul className="scroll-grid">
            {Array.from({ length: 100 }, (_, i) => (
              <li key={i}>{i + 1}</li>
            ))}
          </ul>
        </ScrollArea.Content>
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar className="scrollbar">
        <ScrollArea.Thumb className="scroll-thumb" />
      </ScrollArea.Scrollbar>
      <ScrollArea.Scrollbar className="scrollbar" orientation="horizontal">
        <ScrollArea.Thumb className="scroll-thumb" />
      </ScrollArea.Scrollbar>
      <ScrollArea.Corner />
    </ScrollArea.Root>
  )
}

Scroll Fade

The overflow CSS variables drive a mask that fades the edges.

ScrollAreaScrollFade.tsx
import { ScrollArea } from '@hamur/react/scroll-area'

export default function ScrollAreaScrollFadeExample() {
  return (
    <ScrollArea.Root className="scroll-area scroll-fade">
      <ScrollArea.Viewport className="scroll-viewport">
        <ScrollArea.Content className="scroll-content">
          <p>
            Vernacular architecture is building done outside any academic tradition, and without
            professional guidance. It is not a particular architectural movement or style, but
            rather a broad category, encompassing a wide range and variety of building types, with
            differing methods of construction, from around the world, both historical and extant and
            classical and modern. Vernacular architecture constitutes 95% of the world's built
            environment, as estimated in 1995 by Amos Rapoport, as measured against the small
            percentage of new buildings every year designed by architects and built by engineers.
          </p>
          <p>
            This type of architecture usually serves immediate, local needs, is constrained by the
            materials available in its particular region and reflects local traditions and cultural
            practices. The study of vernacular architecture does not examine formally schooled
            architects, but instead that of the design skills and tradition of local builders, who
            were rarely given any attribution for the work. More recently, vernacular architecture
            has been examined by designers and the building industry in an effort to be more energy
            conscious with contemporary design and construction—part of a broader interest in
            sustainable design.
          </p>
        </ScrollArea.Content>
      </ScrollArea.Viewport>
      <ScrollArea.Scrollbar className="scrollbar">
        <ScrollArea.Thumb className="scroll-thumb" />
      </ScrollArea.Scrollbar>
    </ScrollArea.Root>
  )
}

API reference

3 props across 6 parts, in React syntax. className, style, render are listed once, under Shared props.

ContentScrollArea.Content

A container for the content of the scroll area. Renders a <div>.

Content data attributes
Data attributeDescription
data-scrollingPresent when the user scrolls inside the scroll area.
data-has-overflow-xPresent when the scroll area content is wider than the viewport.
data-has-overflow-yPresent when the scroll area content is taller than the viewport.
data-overflow-x-startPresent when there is overflow on the horizontal start side.
data-overflow-x-endPresent when there is overflow on the horizontal end side.
data-overflow-y-startPresent when there is overflow on the vertical start side.
data-overflow-y-endPresent when there is overflow on the vertical end side.

CornerScrollArea.Corner

A small rectangular area that appears at the intersection of horizontal and vertical scrollbars. Renders a <div>.

RootScrollArea.Root

Groups all parts of the scroll area. Renders a <div>.

Root props
PropTypeDefault
overflowEdgeThresholdThe threshold in pixels that must be passed before the overflow edge attributes are applied.number | Partial<{ xStart: number; xEnd: number; yStart: number; yEnd: number; }>0
Root data attributes
Data attributeDescription
data-scrollingPresent when the user scrolls inside the scroll area.
data-has-overflow-xPresent when the scroll area content is wider than the viewport.
data-has-overflow-yPresent when the scroll area content is taller than the viewport.
data-overflow-x-startPresent when there is overflow on the horizontal start side.
data-overflow-x-endPresent when there is overflow on the horizontal end side.
data-overflow-y-startPresent when there is overflow on the vertical start side.
data-overflow-y-endPresent when there is overflow on the vertical end side.
Root CSS variables
CSS variableDescription
--scroll-area-corner-heightThe scroll area's corner height.
--scroll-area-corner-widthThe scroll area's corner width.

ScrollbarScrollArea.Scrollbar

A vertical or horizontal scrollbar for the scroll area. Renders a <div>.

Scrollbar props
PropTypeDefault
orientationWhether the scrollbar controls vertical or horizontal scroll."horizontal" | "vertical"'vertical'
keepMountedWhether to keep the HTML element in the DOM when the viewport isn't scrollable.booleanfalse
Scrollbar data attributes
Data attributeDescription
data-orientationIndicates the orientation of the scrollbar.
data-hoveringPresent when the pointer is over the scroll area.
data-scrollingPresent when the user scrolls inside the scroll area.
data-has-overflow-xPresent when the scroll area content is wider than the viewport.
data-has-overflow-yPresent when the scroll area content is taller than the viewport.
data-overflow-x-startPresent when there is overflow on the horizontal start side.
data-overflow-x-endPresent when there is overflow on the horizontal end side.
data-overflow-y-startPresent when there is overflow on the vertical start side.
data-overflow-y-endPresent when there is overflow on the vertical end side.
Scrollbar CSS variables
CSS variableDescription
--scroll-area-thumb-heightThe scroll area thumb's height.
--scroll-area-thumb-widthThe scroll area thumb's width.

ThumbScrollArea.Thumb

The draggable part of the scrollbar that indicates the current scroll position. Renders a <div>.

Thumb data attributes
Data attributeDescription
data-orientationIndicates the orientation of the scrollbar.
data-scrollingPresent when the user scrolls inside the scroll area.

ViewportScrollArea.Viewport

The actual scrollable container of the scroll area. Renders a <div>.

Viewport data attributes
Data attributeDescription
data-scrollingPresent when the user scrolls inside the scroll area.
data-has-overflow-xPresent when the scroll area content is wider than the viewport.
data-has-overflow-yPresent when the scroll area content is taller than the viewport.
data-overflow-x-startPresent when there is overflow on the horizontal start side.
data-overflow-x-endPresent when there is overflow on the horizontal end side.
data-overflow-y-startPresent when there is overflow on the vertical start side.
data-overflow-y-endPresent when there is overflow on the vertical end side.
Viewport CSS variables
CSS variableDescription
--scroll-area-overflow-x-startThe distance from the horizontal start edge in pixels.
--scroll-area-overflow-x-endThe distance from the horizontal end edge in pixels.
--scroll-area-overflow-y-startThe distance from the vertical start edge in pixels.
--scroll-area-overflow-y-endThe distance from the vertical end edge in pixels.

Shared props

Every part that renders an element takes these.

Shared props
PropType
classNameCSS class applied to the element, or a function that returns a class based on the component's state.string | ((state: State) => string | undefined)
styleStyle applied to the element, or a function that returns a style object based on the component's state.React.CSSProperties | ((state: State) => React.CSSProperties | undefined)
renderAllows you to replace the component's HTML element with a different tag, or compose it with another component.React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State>

Keyboard and accessibility

Keyboard

ScrollArea adds no keys: Viewport takes focus when its content overflows, and the browser scrolls it with the arrow keys, PageUp, PageDown, Home and End.

Accessibility

What the parts set
PartSetsSo that
Viewporttabindex="0" while the content overflowskeyboard users can focus the region and scroll it
Viewportkeeps its own rolethe scrollable region is not hidden from assistive technology
Scrollbararia-hidden="true"the custom bars are not read; the native scroll position is
Corneraria-hidden="true"the corner piece is not read
Rootrole="presentation"the wrapper adds nothing to what is read
Contentrole="presentation"the inner wrapper adds nothing to what is read

Focus order

  1. Viewport is a tab stop only while its content overflows; the content's own controls follow in order.