Ink 3 has a lot of exciting new features, but unfortunately, there are some breaking changes. If you're migrating your app and running into issues that this guide doesn't cover, feel free to open an issue.
$ npm install ink@next react
Text must be wrapped in a <Text>
component (#299)
There are many more details on this change in the linked PR above, but the TLDR is that all text must be wrapped in a <Text>
component now. Otherwise, Ink will throw an error like this:
Text string "Hello World" must be rendered inside component
If you're used to building apps with React Native, Ink now has the same requirement in regards to text so it should feel familiar to you.
// Before
<Box>Hello World</Box>
// After
<Text>Hello World</Text>
Note: It's allowed to have nested <Text>
components. <Box>
can't be used inside <Text>
component.
Merged <Color>
component functionality into <Text>
(#301)
In Ink 3 there's no more <Color>
component. Instead, you can use the color
and backgroundColor
props directly in <Text>
. The way you specify colors has also changed a bit. Before there was a separate prop for each color, now there are just two props, which accept CSS-like values.
// Before
<Color red>
<Text>Hello World</Text>
</Color>
<Color hex="#ffffff">
<Text>Hello World</Text>
</Color>
<Color white bgGreen>
<Text>Hello World</Text>
</Color>
// After
<Text color="red">Hello World</Text>
<Text color="#ffffff">Hello World</Text>
<Text color="white" backgroundColor="green">Hello World</Text>
Removed <div>
and <span>
(#306)
It was “illegal” to use these tags directly before, but now they're removed completely. If you are using them, switch from <div>
to <Box>
and from <span>
to <Text>
.
Removed unstable__transformChildren
from <Box>
and <Text>
(ab36e7f)
Previously this function was used to transform the string representation of a component's children
. You can achieve the same with the <Transform>
component.
// Before
<Box unstable__transformChildren={children => children.toUpperCase()}>
Hello World
</Box>
// After
<Transform transform={children => children.toUpperCase()}>
<Text>Hello World</Text>
</Transform>
Removed AppContext
, StdinContext
and StdoutContext
in favor of useApp
, useStdin
and useStdout
hooks (055a196)
Hooks are the future.
// Before
import {AppContext, StdinContext, StdoutContext} from 'ink';
const Example = () => (
<AppContext.Consumer>
{appProps => (
<StdinContext.Consumer>
{stdinProps => (
<StdoutContext.Consumer>
{stdoutProps => (
…
)}
</StdoutContext.Consumer>
)}
</StdinContext.Consumer>
)}
</AppContext.Consumer>
);
// After
import {useApp, useStdin, useStdout} from 'ink';
const Example = () => {
const appProps = useApp();
const stdinProps = useStdin();
const stdoutProps = useStdout();
return …;
};
New <Static>
component (#281)
The functionality has remained the same, but the API has changed and performance has significantly improved. The new API looks very similar to the one commonly used in virtual list libraries, like react-tiny-virtual-list
.
// Before
<Static>
{items.map(item => (
<Text key={item.id}>
{item.title}
</Text>
))}
</Static>
// After
<Static items={items}>
{item => (
<Text key={item.id}>
{item.title}
</Text>
)}
</Static>
Log interception (acb6ed2)
Ink 3 intercepts all output coming from console.log
, console.error
and other console
methods to display them above main Ink output.
If this is not the desired behavior, you can disable it using the patchConsole
option:
import {render} from 'ink';
render(<MyApp />, {patchConsole: false});
Use <Transform>
component instead of unstable__transformChildren
(#277)
Ink 3 introduces a new way to transform the output of text components - <Transform>
.
The migration should be painless as it accepts the same transformation function as before.
// Before
<Text unstable__transformChildren={children => children.toUpperCase()}>
Hello World
</Text>;
// After
import {Transform} from 'ink';
<Transform transform={children => children.toUpperCase()}>
<Text>Hello World</Text>
</Transform>;
Note that it's no longer recommended to apply transformations on <Box>
components due to unpredictable rendering results.
Use measureElement
to measure box dimensions (#307)
There's a new function exported by Ink called measureElement
that measures the dimensions of any <Box>
component.
Previously you had to use the undocumented unstable__getComputedWidth
method.
// Before
const Example = () => {
const boxRef = useRef();
useEffect(() => {
const width = boxRef.current.unstable__getComputedWidth();
//=> 100
}, []);
return <Box ref={boxRef}>Hello World</Box>;
};
// After
import {measureElement} from 'ink';
const Example = () => {
const boxRef = useRef();
useEffect(() => {
const {width, height} = measureElement(boxRef.current);
//=> width = 100, height = 1
}, []);
return <Box ref={boxRef}>Hello World</Box>;
};
Previously, <Box>
had a textWrap
property, which would specify if and how text inside that element should be wrapped.
In Ink 3 all text is wrapped by default based on container's dimensions and textWrap
property has moved to <Text>
component instead and is now named wrap
.
It acceps the same values as before.
// Before
<Box textWrap="wrap">Hello World</Box>
<Box textWrap="truncate">Hello World</Box>
// After
<Text>Hello World</Text>
<Text wrap="truncate">Hello World</Text>