v8.0.0

visioncortex/vtracerv8.0.0Oct 3, 2026by sindresorhus

Upgrading?

AI Summary

This major release upgrades the project to React 19.3+, introduces scrollable views via new content offset props, and updates stream typing to generic Node.js streams. It includes extensive fixes for rendering, input handling, and focus management.

Key Highlights

  • Requires React 19.3+
  • Adds `contentOffsetX` and `contentOffsetY` props to `<Box>` for scrollable views
  • Updates `stdin`, `stdout`, and `stderr` to generic Node.js stream types
  • Improves incremental rendering by skipping unchanged line prefixes
  • Enhances input handling by dropping unrecognized terminal control sequences

Breaking Changes

  • React version requirement increased to 19.3+
  • `<Box>` `minWidth` and `maxWidth` props now only accept numbers (percentage strings removed)
  • Stream types for `stdin`, `stdout`, and `stderr` are now generic Node.js streams (TTY properties removed)
  • `useInput` no longer receives unrecognized terminal control sequences

New Features

  • New `contentOffsetX` and `contentOffsetY` props on `<Box>` for building scrollable views
  • New `clientWidth` and `clientHeight` properties in `useBoxMetrics()` and `measureElement()`
  • Accept any Node.js stream for `stdin`, `stdout`, and `stderr` options
  • Skip unchanged line prefixes in incremental rendering mode
  • Drop `ws` dependency in favor of native `WebSocket` for React DevTools
  • Recognize application keypad Enter as `key.return`

Full Release Notes

### Breaking

- Require React 19.3+  7829102
- `minWidth` and `maxWidth` on `<Box>` now only accept numbers ([#1029](https://github.com/vadimdemedes/ink/issues/1029))  7cd7fd9
  - Percentage strings were never documented as supported, and Yoga resolved them against the wrong ancestor
- `stdin`, `stdout`, and `stderr` are now typed as generic Node.js streams ([#981](https://github.com/vadimdemedes/ink/issues/981))  eb82d8f
  - This applies to the `render()` options and to `useStdin()`, `useStdout()`, and `useStderr()`. TTY-only properties like `stdout.columns` are no longer part of the types
- `useInput` no longer receives unrecognized terminal control sequences (#1014)  c76893e
  - Mouse reports, focus in/out events, cursor position reports, and other terminal replies used to arrive in `input` with the ESC stripped, as if typed. They are now dropped

### New

- Add [`contentOffsetX`](https://github.com/vadimdemedes/ink#contentoffsetx) and [`contentOffsetY`](https://github.com/vadimdemedes/ink#contentoffsety) props to `<Box>` for building scrollable views ([#765](https://github.com/vadimdemedes/ink/issues/765))  3ba5828
  - Combine with `overflow="hidden"`. See the [scroll example](https://github.com/vadimdemedes/ink/tree/master/examples/scroll)
- Add [`clientWidth`](https://github.com/vadimdemedes/ink#clientwidth) and [`clientHeight`](https://github.com/vadimdemedes/ink#clientheight) to `useBoxMetrics()` and [`measureElement()`](https://github.com/vadimdemedes/ink#measureelementref) (#988)  3ba5828
  - The element size excluding borders, which is the space its content can occupy
- Accept any Node.js stream for the `stdin`, `stdout`, and `stderr` options of `render()` ([#981](https://github.com/vadimdemedes/ink/issues/981))  eb82d8f
  - For example, `PassThrough` or other `Readable`/`Writable` streams. Raw mode is used only when `stdin` is a TTY with `setRawMode()`
- Skip unchanged line prefixes in [`incrementalRendering`](https://github.com/vadimdemedes/ink#incrementalrendering) mode (#1036)  91eb50a
  - Only the changed part of a line is written, which reduces output and flicker
- Drop the `ws` dependency in favor of the native `WebSocket` for React DevTools ([#976](https://github.com/vadimdemedes/ink/issues/976))  33567ed
- Recognize application keypad Enter as `key.return`  b73ebf4

### Fixes

#### Rendering

- Preserve scrollback when clearing the viewport (#994)  fe1d123
- Preserve terminal history after `clear()`  494ebeb
- Restore the unchanged frame when rerendering after `clear()`  fc358c2
- Redraw the frame when the terminal loses rows (#1025)  f603aeb
- Keep content above the frame when rows shrink while the cursor is shown (#1031)  c800284
- Keep the cursor on the last line when output has no trailing newline (#982)  cdc18fa
- Restore the terminal cursor below the frame on exit  06385e9
- Preserve the cursor position when its component skips rendering  013feb2
- Fix incremental rendering of single-line updates, new blank rows, and changed rows (#1039)  9a501e4 507c0c9 509ea75
- Fix overflow clipping when both the shorthand and an explicit axis are set, and preserve `<Transform>` line indices when clipping  4f3c7aa
- Fix background color inheritance for `<Static>` and nested `<Text>`  753a5f8
- Fix fractional percentages being truncated in layout sizes, and restore layout defaults when style props are `undefined`  274b15a
- Preserve visibility across Suspense transitions  fc685bc
- Call `onRender` after the frame is written  83d7de5

#### `<Static>`

- Stop replaying `<Static>` output on full-clear frames (#1005)  d661543
- Replay `<Static>` output when resuming re-enters the alternate screen (#1012)  9235028
- Fix repeated padding, ignored margins, and output inside hidden ancestors  793fe59
- Keep `<Static>` output after abandoned concurrent renders  8678b76
- Reset captured `<Static>` output when its identity changes  cfdd9e6
- Preserve blank `<Static>` rows  f6b2620 c0fa4ef 5911f44
- Fix dangling `staticNode` reference on indirect subtree removal (#979)  5448e6b

#### Text

- Truncate each line of multi-line text separately (#1006)  4b44934
- Keep text at its natural width when there is no room to wrap (#1022)  36f5624
- Fix multi-line `<Text>` vanishing when it starts above the top of the output (#1001)  77aba4a
- Strip control characters (except tab and newline) from text content (#1020)  405f751 2fbc26a
- Expand tabs, and fix CRLF text overwriting box borders and zero-width spaces overwriting surrounding output  32dc266
- Preserve ANSI styles across explicit newlines  b419e5c
- Preserve combining marks across nested text styles  80b1c9c
- Normalize colon and C1 SGR sequences before layout (#1019)  b0dfd61 9dfe137 7fe1577
- Preserve styles and columns on clipped or overwritten wide characters  f7e57a5 064df65
- Remeasure text when its wrapping mode or `<Transform>` wrap points change  fc685bc 9c323f6
- Preserve the available width when measuring truncated text  1e57b23
- Fix crashes from invalid color names, and whitespace handling in RGB colors  3be9ed7

#### Input

- Fix legacy keyboard modifiers, modified SS3 keys, and Kitty keyboard parsing and detection  2ee828c
  - `reportAssociatedText` now enables `reportAllKeysAsEscapeCodes` automatically
- Handle Ctrl+C that arrives together with ordinary input  13707d2
- Do not mutate the caller's buffer when parsing Meta keys  36d7739
- Keep `onKittyQueryResponse` stable across `rerender()` calls (#1007)  70beca5
- Defer input hook side effects while the terminal is suspended (#1016)  61004d7
- Make `suspendTerminal()` handles idempotent, and do not restore input modes that were released or belong to an unmounted app  a7297c4 b35e89a c613707
- Preserve output during non-interactive terminal suspension  a6789fb

#### Focus

- Treat components that share a focus ID as one Tab stop (#1026)  02ae1e5
- Make `disableFocus()` blur the focused component as documented, and respect it when new components auto-focus  d130588
- Prevent collisions in automatically generated focus IDs  d130588
- Treat an empty string as a valid focus ID  f6f7dc7

#### Other

- Fix screen-reader output: semantic text and labels, empty `<Transform>` labels, rewrapping when the terminal widens, and restoring output after console writes (#1028)  f480301 bebfe2d
- Fix error source excerpts for file URLs and multiline messages, and treat non-Error throws as rendering failures  81e2451
- Fix `renderToString()` swallowing thrown `undefined`, and run effect cleanup when output rendering fails  9f7c1d0
- Fix `useWindowSize()` missing resizes before it subscribes  fab670b
- Track box metrics when a child attaches the ref after mount  53244dc
- Reset `useAnimation()` values while paused  f25d312
- Use defaults for `render()` options that are `undefined`  659249d
- Fix unbounded text caches ([#986](https://github.com/vadimdemedes/ink/issues/986))  ad9e3ea
- Fix `wrapText` cache returning results for the wrong text or width (#998)  3809acc
- Free the root Yoga node on unmount (#999)  064b4f6
- Avoid retaining an exit listener when calling `waitUntilExit()` after unmount  1fcd380

---

## Migration guide

### React 19.3

Upgrade `react` (and `@types/react`) to 19.3 or later.

### `minWidth` and `maxWidth`

Use a number. If you need a relative minimum or maximum width, compute it from [`useWindowSize()`](https://github.com/vadimdemedes/ink#usewindowsize) or [`useBoxMetrics()`](https://github.com/vadimdemedes/ink#useboxmetricsref) of the parent.

```diff
-<Box minWidth="50%">
+<Box minWidth={Math.floor(columns / 2)}>
```

### Stream types

`useStdout().stdout` is now typed as `NodeJS.WritableStream`, so TTY properties like `columns` and `rows` are no longer available in the types. Use [`useWindowSize()`](https://github.com/vadimdemedes/ink#usewindowsize) instead, which also re-renders on resize.

```diff
-const {stdout} = useStdout();
-const width = stdout.columns;
+const {columns: width} = useWindowSize();
```

### Control sequences in `useInput`

If your `useInput` handler parsed mouse reports, focus events, or other terminal replies from `input`, it will no longer receive them. Keys that Ink recognizes, including Kitty keyboard protocol events, are not affected.

---

https://github.com/vadimdemedes/ink/compare/v7.1.1...v8.0.0

Related Repositories