Skip to content

Hooks

inkx provides the same hooks as Ink, plus layout feedback hooks.

useContentRect

inkx only - The key addition. Returns the computed dimensions of the component's container.

tsx
import { Box, Text, useContentRect } from "inkx"

function SizedBox() {
  const { width, height, x, y } = useContentRect()

  return (
    <Box borderStyle="single">
      <Text>
        Size: {width}x{height}
      </Text>
      <Text>
        Position: ({x}, {y})
      </Text>
    </Box>
  )
}

Note

useLayout is a deprecated alias for useContentRect. Both work identically, but prefer useContentRect for new code.

Return Value

PropertyTypeDescription
widthnumberComputed width in characters
heightnumberComputed height in lines
xnumberX position from left edge
ynumberY position from top edge

First Render Behavior

On the first render, dimensions are { width: 0, height: 0, x: 0, y: 0 }. This is because layout hasn't been computed yet. The component will immediately re-render with correct values.

tsx
function Header() {
  const { width } = useContentRect()

  // Guard against first render if needed
  if (width === 0) return null

  return <Text>{"=".repeat(width)}</Text>
}

In practice, both renders happen before the first paint, so this is usually invisible.

useTerm

inkx only - Access the Term instance for terminal capabilities and styling.

tsx
import { useTerm } from "inkx"

function ColoredOutput() {
  const term = useTerm()

  return (
    <Box>
      <Text>{term.green("Success!")} Operation completed.</Text>
      <Text>
        Terminal size: {term.columns}x{term.rows}
      </Text>
    </Box>
  )
}

Return Value

Returns the Term instance passed to render(). Provides:

Property/MethodDescription
columnsTerminal width
rowsTerminal height
hasColor()Check if terminal supports colors
Color methodsred(), green(), bold(), etc.

useInput

Handle keyboard input.

tsx
import { useInput } from "inkx"

function App() {
  const [count, setCount] = useState(0)

  useInput((input, key) => {
    if (key.upArrow) setCount((c) => c + 1)
    if (key.downArrow) setCount((c) => c - 1)
    if (input === "q") process.exit()
  })

  return <Text>Count: {count}</Text>
}

Parameters

tsx
useInput(
  (input: string, key: Key) => void,
  options?: { isActive?: boolean }
)

Key Object

PropertyTypeDescription
upArrowbooleanUp arrow pressed
downArrowbooleanDown arrow pressed
leftArrowbooleanLeft arrow pressed
rightArrowbooleanRight arrow pressed
returnbooleanEnter/Return pressed
escapebooleanEscape pressed
ctrlbooleanControl key held
shiftbooleanShift key held
metabooleanMeta/Command key held
tabbooleanTab pressed
backspacebooleanBackspace pressed
deletebooleanDelete pressed

useApp

Access app-level controls.

tsx
import { useApp } from "inkx"

function App() {
  const { exit } = useApp()

  useInput((input) => {
    if (input === "q") exit()
  })

  return <Text>Press q to quit</Text>
}

Return Value

PropertyTypeDescription
exit(error?: Error) => voidExit the app

useStdout

Access stdout stream and dimensions.

tsx
import { useStdout } from "inkx"

function App() {
  const { stdout, write } = useStdout()

  return (
    <Text>
      Terminal: {stdout.columns}x{stdout.rows}
    </Text>
  )
}

Return Value

PropertyTypeDescription
stdoutNodeJS.WriteStreamstdout stream
write(data: string) => voidWrite directly to stdout

useStdin

Access stdin stream.

tsx
import { useStdin } from "inkx"

function App() {
  const { stdin, setRawMode, isRawModeSupported } = useStdin()
  // ...
}

Return Value

PropertyTypeDescription
stdinNodeJS.ReadStreamstdin stream
setRawMode(mode: boolean) => voidEnable/disable raw mode
isRawModeSupportedbooleanWhether raw mode is supported

useFocusable

Returns focus state for the nearest focusable ancestor. The component must be rendered inside a <Box focusable> with a testID.

tsx
import { useFocusable, Box, Text } from "inkx"

function FocusableItem({ label }: { label: string }) {
  const { focused } = useFocusable()

  return (
    <Box testID={label} focusable borderStyle={focused ? "double" : "single"}>
      <Text>{label}</Text>
    </Box>
  )
}

Return Value

PropertyTypeDescription
focusedbooleanWhether this component currently has focus
focus() => voidProgrammatically focus this component
blur() => voidProgrammatically blur this component
focusOrigin"keyboard" | "mouse" | "programmatic" | nullHow focus was acquired

Focus behavior is configured via Box props: focusable, autoFocus, focusScope, onFocus, onBlur, onKeyDown.

useFocusWithin

Returns whether any descendant of the specified Box (by testID) has focus.

tsx
import { useFocusWithin } from "inkx"

function Sidebar() {
  const hasFocus = useFocusWithin("sidebar")

  return (
    <Box testID="sidebar" borderColor={hasFocus ? "blue" : "gray"}>
      <FocusableItem testID="item1" />
      <FocusableItem testID="item2" />
    </Box>
  )
}

useFocusManager

Access the focus manager for programmatic focus control.

tsx
import { useFocusManager } from "inkx"

function App() {
  const { activeId, focusNext, focusPrev, focus, blur } = useFocusManager()

  return (
    <Box flexDirection="column">
      <Text>Active: {activeId ?? "none"}</Text>
      <FocusableItem label="First" />
      <FocusableItem label="Second" />
      <FocusableItem label="Third" />
    </Box>
  )
}

Return Value

PropertyTypeDescription
activeIdstring | nulltestID of the currently focused node
activeElementInkxNode | nullThe currently focused node
focusedbooleanWhether any node has focus
focus(id: string) => voidFocus a specific component by testID
focusNext() => voidFocus next focusable component
focusPrev() => voidFocus previous focusable component
blur() => voidClear focus from all components

Released under the MIT License.