Hooks

Reference for all React hooks in @visulima/tui/react: useInput, usePaste, useMouse, useTextInput, useCursor, useScrollable, useFocus, useApp, and more

Hooks

Use these hooks inside components rendered with render(). Hooks that rely on the full app event emitter are marked as render()-mode only.

import { useApp, useCursor, useFocus, useFocusManager, useInput, useMouse, usePaste, useScrollable, useTextInput } from "@visulima/tui/react";

useInput

Subscribe to keyboard input.

useInput((input, key) => {
    if (key.upArrow) moveUp();
    if (key.downArrow) moveDown();
    if (key.return) submit();
    if (key.escape) cancel();
    if (key.ctrl && input === "c") exit();
});

key Fields

FieldType
upArrowboolean
downArrowboolean
leftArrowboolean
rightArrowboolean
returnboolean
backspaceboolean
deleteboolean
pageUpboolean
pageDownboolean
homeboolean
endboolean
tabboolean
shiftboolean
escapeboolean
ctrlboolean
metaboolean

usePaste

Subscribe to bracketed paste events.

usePaste((text) => {
    handlePaste(text);
});

When at least one active usePaste listener exists, pasted text is routed to usePaste and not forwarded to useInput. If no paste listener is active, paste falls back to useInput.

Options

usePaste(handler, { isActive: false });
OptionTypeDefault
isActivebooleantrue

useMouse (Ratatat-only)

Subscribe to mouse events.

useMouse((event) => {
    // event.button: left | right | middle | scrollUp | scrollDown
    // event.x, event.y are 0-based terminal coordinates
    if (event.button === "left") onClick(event.x, event.y);
});

Event Shape

FieldTypeNotes
xnumber0-based column
ynumber0-based row
buttonstringleft/right/middle/scrollUp/scrollDown
shiftbooleanmodifier
ctrlbooleanmodifier
metabooleanmodifier

useTextInput (Ratatat-only)

Managed text input with cursor and editing shortcuts.

const { value, cursor, clear } = useTextInput({
    onSubmit: (v) => send(v),
});

return (
    <Text>
        {value.slice(0, cursor)}
        <Text inverse>{value[cursor] ?? " "}</Text>
        {value.slice(cursor + 1)}
    </Text>
);

Options

OptionTypeDefault
initialValuestring''
onSubmit(v: string) => void
onChange(v: string) => void
isActivebooleantrue

Return Value

FieldType
valuestring
cursornumber
setValue(v: string) => void
clear() => void

Supported editing keys: arrows, Home/End, Backspace/Delete, Ctrl+A/E/U/K/W, Enter, paste.

useScrollable (Ratatat-only)

Virtual scrolling state for fixed-height viewports.

const viewportHeight = 20;
const scroll = useScrollable({
    viewportHeight,
    contentHeight: items.length,
});

useInput((_input, key) => {
    if (key.upArrow) scroll.scrollUp();
    if (key.downArrow) scroll.scrollDown();
    if (key.pageUp) scroll.scrollBy(-10);
    if (key.pageDown) scroll.scrollBy(10);
    if (key.home) scroll.scrollToTop();
    if (key.end) scroll.scrollToBottom();
});

const visible = items.slice(scroll.offset, scroll.offset + viewportHeight);

Return Value

offset, scrollUp, scrollDown, scrollBy, scrollToTop, scrollToBottom, atTop, atBottom.

useFocus

Register a focusable component.

const { isFocused, focus } = useFocus({ id: "search", autoFocus: true });

Tab/Shift+Tab focus cycling is wired automatically by render().

useFocusManager

Programmatic focus control.

const { focusNext, focusPrevious, focus, activeId, enableFocus, disableFocus } = useFocusManager();

useApp

Lifecycle controls.

const { exit, quit } = useApp();

exit() and quit() are equivalent.

useWindowSize

Returns { columns, rows } and updates on terminal resize.

const { columns, rows } = useWindowSize();

This hook relies on the full app event emitter and is intended for render() mode.

useStdout / useStderr

Write outside the rendered frame.

const { write } = useStdout();
const { write: writeErr } = useStderr();

write("log line\n");
writeErr("warning\n");

useStdin

Access stdin and raw mode controls.

const { stdin, setRawMode, isRawModeSupported } = useStdin();

useBoxMetrics

Read computed layout metrics from a Box ref.

const ref = useRef(null);
const { width, height, left, top, hasMeasured } = useBoxMetrics(ref);

return <Box ref={ref}>...</Box>;

Returns zeroed metrics until first layout pass.

This hook relies on the full app event emitter and is intended for render() mode.

measureElement

Imperative element measurement.

const { width, height } = measureElement(ref.current);

useCursor

Imperative cursor positioning. Use this when you need precise control over cursor placement, for example with IME (Input Method Editor) support where you need to account for wide characters.

const { setCursorPosition } = useCursor();

const prompt = "> ";
setCursorPosition({ x: stringWidth(prompt + text), y: 1 });

return (
    <Box flexDirection="column">
        <Text>Header</Text>
        <Text>{prompt}{text}</Text>
    </Box>
);

setCursorPosition

ArgumentTypeDescription
position{ x: number, y: number } or undefinedAbsolute position, or undefined to hide

Notes:

  • x and y are 0-based coordinates relative to the top-left of the rendered output.
  • Use stringWidth() from @visulima/string for correct column calculation with wide characters.
  • The cursor is automatically hidden when the component using useCursor unmounts.
  • For most text input use cases, prefer the declarative <Cursor /> component instead.

Compatibility Stubs

useIsScreenReaderEnabled

Always returns false.

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