Ink Compatibility

Ink API parity matrix, render option differences, and native-only exports in @visulima/tui/react

Ink Compatibility

@visulima/tui targets Ink API compatibility for core component and hook workflows, with a few documented stubs and behavior differences.

Core API Parity

ExportStatusNotes
render()Returns { rerender, unmount, waitUntilExit, app, input }
BoxYoga-backed layout
TextCore style props supported
Newlinecount supported
SpacerFlex grow spacer
StaticAppend-only semantics
TransformTransform callback support
renderToString()Synchronous snapshot
measureElement()Returns { x, y, width, height }
useApp()exit + quit
useInput()Arrows, Enter, Escape, Ctrl, Meta, paging keys
usePaste()Bracketed paste routing
useFocus()Focus state and focus(id)
useFocusManager()Focus navigation methods
useStdin()Raw mode helpers
useStdout()Buffered while app is running
useStderr()Buffered while app is running
useBoxMetrics()Layout metrics + hasMeasured (intended for render() mode)
useWindowSize(){ columns, rows } (intended for render() mode)
CursorDeclarative cursor; inline mode + anchor mode
useCursor()Imperative cursor positioning with IME support
useAnimation()Shared-timer animation driver: frame, time, delta, reset
LinkPorted from ink-link, OSC 8 clickable hyperlinks
ProgressBarPorted from ink-progress-bar, percent-based fill
SelectInputPorted from ink-select-input, interactive list selection
TextInputInspired by ink-ui, single-line text entry with cursor
ConfirmInputInspired by ink-ui, Y/N confirmation prompt
MultiSelectInspired by ink-ui, multi-choice selection with checkboxes
BadgeInspired by ink-ui, uppercase colored label
StatusMessageInspired by ink-ui, status icon + message
AlertInspired by ink-ui, bordered variant alert box
UnorderedListInspired by ink-ui, bullet list with nesting
OrderedListInspired by ink-ui, numbered list with nesting
useIsScreenReaderEnabled()Enabled via render() option or INK_SCREEN_READER env var

Render Option Differences

render() accepts Ink-style options, but these are currently ignored:

  • concurrent
  • patchConsole
  • exitOnCtrlC
  • incrementalRendering
  • debug

maxFps is used.

Mouse Support (Ink Layer)

Ported from @zenobius/ink-mouse. Import from @visulima/tui.

ExportDescription
<MouseProvider>Enables mouse tracking for descendant components
<Fullscreen>Terminal-filling Box container
useMouseContext()Full mouse context (position, events, actions)
useMousePosition()Reactive mouse coordinates
useMouseAction()Current action (click/scroll/drag)
useOnMouseClick(ref)Click detection on an element
useOnMouseHover(ref)Hover detection on an element
useOnMouseState(ref)Combined { hovering, clicking } state
useElementPosition()Absolute element position via Yoga tree
useElementDimensions()Element width and height
isIntersecting()Hit-test utility

See the Mouse Support page for full documentation.

Scroll Components (Ink Layer)

Ported from ink-scroll-view, @byteland/ink-scroll-bar, and ink-scroll-list. Import from @visulima/tui.

ExportDescription
<ScrollView>Scrollable viewport with imperative ref for scroll control
<ControlledScrollView>Controlled variant — parent owns scrollOffset
<ScrollBar>Vertical scroll bar indicator (border or inset placement)
<ScrollBarBox>Box with integrated scroll bar on one border
<ScrollList>ScrollView + externally controlled selection with auto-scroll

See the Scroll Components page for full documentation.

CSS-Level Scroll and Measurement APIs

Ported from jacob314/ink (Google's Gemini CLI fork). These extend Ink's Box with CSS-level overflow scrolling, sticky headers, and advanced measurement.

ExportDescription
Box overflow="scroll"CSS-level overflow scrolling with integrated scrollbar rendering
Box stickySticky headers that pin to viewport edges during scroll
Box scrollbarShow/hide scrollbar on scrollable containers
ResizeObserverBrowser-like API for observing element size changes
getBoundingBox()Scroll-aware absolute position and dimensions
getInnerWidth() / getInnerHeight()Inner dimensions excluding borders
getScrollHeight() / getScrollWidth()Total scroll content dimensions
getScrollTop() / getScrollLeft()Current scroll position
calculateScroll()Compute scroll state for a scrollable element
getVerticalScrollbarBoundingBox()Scrollbar thumb position for hit testing
getHorizontalScrollbarBoundingBox()Horizontal scrollbar position
setStringWidthFunction()Replace the string width function for custom terminals
getRelativeTop() / getRelativeLeft()Position relative to an ancestor element

Native Renderer API (No Ink Equivalent)

ExportDescription
useScrollable()Virtual scrolling state helper
useMouse()Mouse click/wheel events with modifiers
useTextInput()Managed text editing hook
SpinnerAnimated spinner component
renderInline()React inline rendering mode
createInlineLoop()Raw-buffer inline rendering loop
Renderer / TerminalGuardRaw-buffer runtime primitives
render / cleanup / screen / keys / waitFor / flush (test)Testing utilities with mock streams, screen queries, keyboard simulation, and async assertions (@visulima/tui/test)

Architectural Differences vs Ink

ConcernInk@visulima/tui
Render strategyJS string rendererRust diff over Uint32Array
Screen modeInline rewrite modelAlternate screen model
patchConsoleIntegratedNot implemented
Screen reader hookFunctionalFunctional (opt-in)
Cursor hookFunctionalFunctional

compat-test/ Status

The compat-test/ directory tracks runnable Ink example ports.

  • Most files are direct ports with import-path changes
  • Two files include small TypeScript typing fixes from upstream examples (use-focus.tsx, use-focus-with-id.tsx)

Run examples manually:

node --import @oxc-node/core/register compat-test/counter.tsx
node --import @oxc-node/core/register compat-test/chat.tsx
Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues