opentui

Build terminal UIs with OpenTUI. Covers Core, frameworks, components, application APIs, testing, extensions, integrations, deployment, and public API lookup.

Install
npx skills add 'https://github.com/anomalyco/opentui/tree/main/packages/web/src/content'
Download bundle ↓
main · ac753b4Scanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗

docs/components/scrollbox.mdx

docs/components/scrollbox.mdxBrowse 89 files
View on GitHub
← Back to SKILL.md

title: ScrollBox description: Scroll and cull child content in a bounded viewport

ScrollBox

ScrollBox scrolls arbitrary child renderables and manages its own ScrollBar instances. Use a standalone ScrollBar only when another model owns the scroll position.

Availability

FieldAvailability
Package@opentui/core
Core renderableScrollBoxRenderable
React<scrollbox> (automatic)
Solid<scrollbox> (automatic)
StatusBuilt in

Basic usage

Renderable API

import { ScrollBoxRenderable, TextRenderable, BoxRenderable, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const scrollbox = new ScrollBoxRenderable(renderer, {
  id: "scrollbox",
  width: 40,
  height: 20,
})

// Add content to the scrollbox
for (let i = 0; i < 100; i++) {
  scrollbox.add(
    new BoxRenderable(renderer, {
      id: `item-${i}`,
      width: "100%",
      height: 2,
      backgroundColor: i % 2 === 0 ? "#292e42" : "#2f3449",
    }),
  )
}

renderer.root.add(scrollbox)

A bordered list of source files initially shows its first five rows:

offset: 0 / 7
┌──────────────────────────────┐
│01  src/index.ts             ▀│
│02  src/app.ts                │
│03  src/layout.ts             │
│04  src/theme.ts              │
│05  src/events.ts             │
└──────────────────────────────┘

Sticky scroll

Enable sticky scroll to keep content pinned to an edge as new content arrives. Set both stickyScroll and stickyStart because stickyStart has no default.

const scrollbox = new ScrollBoxRenderable(renderer, {
  id: "logs",
  width: 60,
  height: 20,
  stickyScroll: true,
  stickyStart: "bottom", // New content will keep the view scrolled to bottom
})

Sticky positions

  • "bottom": Stay scrolled to the bottom
  • "top": Stay scrolled to the top
  • "left": Stay scrolled to the left
  • "right": Stay scrolled to the right

When you scroll away from the sticky position, sticky behavior pauses until you scroll back to the sticky edge.

Bidirectional scrolling

Enable scrolling in both directions:

const scrollbox = new ScrollBoxRenderable(renderer, {
  id: "canvas",
  width: 60,
  height: 30,
  scrollX: true,
  scrollY: true,
})

By default, scrollY is true and scrollX is false.

Viewport culling

Enable viewport culling to skip offscreen children in large content. When enabled, ScrollBox renders only visible children:

const scrollbox = new ScrollBoxRenderable(renderer, {
  id: "large-list",
  width: 40,
  height: 20,
  viewportCulling: true, // Only render visible items
})

Viewport culling skips render calls for offscreen children, so their renderBefore and renderAfter hooks do not run. Do not make layout or state depend on render hooks. Disable viewportCulling if every child must run a render hook.

Customizing scrollbars

Style the scrollbars using nested options:

const scrollbox = new ScrollBoxRenderable(renderer, {
  id: "styled-scroll",
  width: 40,
  height: 20,
  scrollbarOptions: {
    showArrows: true,
    trackOptions: {
      foregroundColor: "#7aa2f7",
      backgroundColor: "#414868",
    },
  },
  // Or customize vertical and horizontal separately
  verticalScrollbarOptions: {
    trackOptions: { backgroundColor: "#333" },
  },
  horizontalScrollbarOptions: {
    trackOptions: { backgroundColor: "#333" },
  },
})

Customizing sub-components

ScrollBox contains several internal components that you can style individually:

const scrollbox = new ScrollBoxRenderable(renderer, {
  id: "custom-scroll",
  width: 40,
  height: 20,
  rootOptions: {
    backgroundColor: "#24283b",
  },
  wrapperOptions: {
    backgroundColor: "#1f2335",
  },
  viewportOptions: {
    backgroundColor: "#1a1b26",
  },
  contentOptions: {
    backgroundColor: "#16161e",
  },
})

Scroll methods

scrollBy

Scroll by a relative amount:

// Scroll down 5 lines
scrollbox.scrollBy(5)

// Scroll with both x and y
scrollbox.scrollBy({ x: 10, y: 5 })

// Scroll by viewport (page)
scrollbox.scrollBy(1, "viewport")

scrollTo

Scroll to an absolute position:

// Scroll to top
scrollbox.scrollTo(0)

// Scroll to specific position
scrollbox.scrollTo({ x: 0, y: 100 })

The same list after scrollTo(5):

offset: 5 / 7
┌──────────────────────────────┐
│06  src/input.ts              │
│07  src/scroll.ts             │
│08  src/render.ts             │
│09  src/state.ts             ▀│
│10  src/config.ts             │
└──────────────────────────────┘

scrollChildIntoView

Scroll the minimum distance needed to show a nested child in the viewport. The method uses DOM-style "nearest" behavior. If the child already fits, the call is a no-op. An oversized child also stays in place when it extends beyond both edges of an axis. Otherwise, the method scrolls to reveal the nearest edge.

scrollbox.scrollChildIntoView("table-row-42")

Use it when you focus an offscreen element, such as a search result or a new form field. The method moves the scroll position only as much as necessary.

Keyboard navigation

When focused, ScrollBox responds to keyboard input:

  • Arrow keys: Move by one fifth of the active viewport.
  • Page Up/Down: Move by one half of the vertical viewport.
  • Home/End: Move to the start or end.

Properties

PropertyTypeDefaultDescription
scrollXbooleanfalseEnable horizontal scrolling
scrollYbooleantrueEnable vertical scrolling
stickyScrollbooleanfalseKeep scroll position pinned to an edge
stickyStart"top" | "bottom" | "left" | "right"-Which edge to stick to
viewportCullingbooleantrueOnly render visible children
scrollAccelerationScrollAcceleration-Custom scroll acceleration algorithm
rootOptionsBoxOptions-Style options for root container
wrapperOptionsBoxOptions-Style options for wrapper
viewportOptionsBoxOptions-Style options for viewport
contentOptionsBoxOptions-Style options for content container
scrollbarOptionsScrollBarOptions-Options for both scrollbars
verticalScrollbarOptionsScrollBarOptions-Options for vertical scrollbar only
horizontalScrollbarOptionsScrollBarOptions-Options for horizontal scrollbar only

Additional properties

PropertyTypeDescription
scrollTopnumberCurrent vertical scroll position (get/set)
scrollLeftnumberCurrent horizontal scroll position (get/set)
scrollWidthnumberTotal scrollable width (read-only)
scrollHeightnumberTotal scrollable height (read-only)

Internal components

ScrollBox exposes its internal components for advanced use:

scrollbox.wrapper // BoxRenderable - outer wrapper
scrollbox.viewport // BoxRenderable - visible area
scrollbox.content // ContentRenderable - holds children
scrollbox.horizontalScrollBar // ScrollBarRenderable
scrollbox.verticalScrollBar // ScrollBarRenderable

Read Layout for viewport sizing. Read Interaction, focus, and selection for focus, wheel input, drag selection, and event propagation.