UNPKG

45.1 kBMarkdownView Raw
1[![](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
2
3---
4
5<div align="center">
6 <br>
7 <br>
8 <img width="240" alt="Ink" src="media/logo.png">
9 <br>
10 <br>
11 <br>
12</div>
13
14> React for CLIs. Build and test your CLI output using components.
15
16[![Build Status](https://github.com/vadimdemedes/ink/workflows/test/badge.svg)](https://github.com/vadimdemedes/ink/actions)
17[![npm](https://img.shields.io/npm/dm/ink?logo=npm)](https://npmjs.com/package/ink)
18
19Ink provides the same component-based UI building experience that React offers in the browser, but for command-line apps.
20It uses [Yoga](https://github.com/facebook/yoga) to build Flexbox layouts in the terminal, so most CSS-like props are available in Ink as well.
21If you are already familiar with React, you already know Ink.
22
23Since Ink is a React renderer, it means that all features of React are supported.
24Head over to [React](https://reactjs.org) website for documentation on how to use it.
25Only Ink's methods will be documented in this readme.
26
27**Note:** This is documentation for Ink 4. If you're looking for docs on Ink 3, check out [this release](https://github.com/vadimdemedes/ink/tree/v3.2.0).
28
29---
30
31<div align="center">
32 <p>
33 <p>
34 <sup>
35 <a href="https://opencollective.com/vadimdemedes">My open source work is supported by the community ❤️</a>
36 </sup>
37 </p>
38 <sup>Special thanks to:</sup>
39 <br>
40 <a href="https://workos.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=ink&utm_source=github">
41 <div>
42 <img src="https://vadimdemedes.com/github/workos.svg" width="200" alt="WorkOS">
43 </div>
44 <b>Your app, enterprise-ready.</b>
45 <div>
46 <sub>Start selling to enterprise customers with just a few lines of code.</sub>
47 <br>
48 <sup>Add Single Sign-On (and more) in minutes instead of months.</sup>
49 </div>
50 </a>
51 </p>
52 <br>
53 <br>
54</div>
55
56## Install
57
58```sh
59npm install ink react
60```
61
62## Usage
63
64```jsx
65import React, {useState, useEffect} from 'react';
66import {render, Text} from 'ink';
67
68const Counter = () => {
69 const [counter, setCounter] = useState(0);
70
71 useEffect(() => {
72 const timer = setInterval(() => {
73 setCounter(previousCounter => previousCounter + 1);
74 }, 100);
75
76 return () => {
77 clearInterval(timer);
78 };
79 }, []);
80
81 return <Text color="green">{counter} tests passed</Text>;
82};
83
84render(<Counter />);
85```
86
87<img src="media/demo.svg" width="600">
88
89You can also check it out live on [repl.it sandbox](https://ink-counter-demo.vadimdemedes.repl.run/).
90Feel free to play around with the code and fork this repl at [https://repl.it/@vadimdemedes/ink-counter-demo](https://repl.it/@vadimdemedes/ink-counter-demo).
91
92## Who's Using Ink?
93
94- [Cloudflare's Wrangler](https://github.com/cloudflare/wrangler2) - The CLI for Cloudflare Workers.
95- [Gatsby](https://www.gatsbyjs.org) - Gatsby is a modern web framework for blazing fast websites.
96- [tap](https://node-tap.org) - A Test-Anything-Protocol library for JavaScript.
97- [Terraform CDK](https://github.com/hashicorp/terraform-cdk) - CDK (Cloud Development Kit) for HashiCorp Terraform.
98- [Twilio's SIGNAL](https://github.com/twilio-labs/plugin-signal2020) - CLI for Twilio's SIGNAL conference. [Blog post](https://www.twilio.com/blog/building-conference-cli-in-react).
99- [Typewriter](https://github.com/segmentio/typewriter) - Generates strongly-typed [Segment](https://segment.com) analytics clients from arbitrary JSON Schema.
100- [Prisma](https://www.prisma.io) - The unified data layer for modern applications.
101- [Wallace](https://www.projectwallace.com) - Pretty CSS analytics.
102- [Blitz](https://blitzjs.com) - The Fullstack React Framework.
103- [New York Times](https://github.com/nytimes/kyt) - NYT uses Ink `kyt` - a toolkit that encapsulates and manages the configuration for web apps.
104- [tink](https://github.com/npm/tink) - Next-generation runtime and package manager.
105- [Inkle](https://github.com/jrr/inkle) - Wordle game.
106- [loki](https://github.com/oblador/loki) - Visual regression testing for Storybook.
107- [Bit](https://github.com/teambit/bit) - Build, distribute and collaborate on components.
108- [Remirror](https://github.com/remirror/remirror) - Your friendly, world-class editor toolkit.
109- [Prime](https://github.com/birkir/prime) - Open source GraphQL CMS.
110- [Splash](https://github.com/Shopify/polaris-react/tree/master/scripts/splash) - Observe the splash zone of a change across the Shopify's [Polaris](https://polaris.shopify.com) component library.
111- [emoj](https://github.com/sindresorhus/emoj) - Find relevant emojis.
112- [emma](https://github.com/maticzav/emma-cli) - Find and install npm packages.
113- [swiff](https://github.com/simple-integrated-marketing/swiff) - Multi-environment command line tools for time-saving web developers.
114- [share](https://github.com/marionebl/share-cli) - Quickly share files.
115- [Kubelive](https://github.com/ameerthehacker/kubelive) - CLI for Kubernetes to provide live data about the cluster and its resources.
116- [changelog-view](https://github.com/jdeniau/changelog-view) - View changelogs.
117- [cfpush](https://github.com/mamachanko/cfpush) - An interactive Cloud Foundry tutorial.
118- [startd](https://github.com/mgrip/startd) - Turn your React component into a web app.
119- [wiki-cli](https://github.com/hexrcs/wiki-cli) - Search Wikipedia and read summaries.
120- [garson](https://github.com/goliney/garson) - Build interactive config-based command-line interfaces.
121- [git-contrib-calendar](https://github.com/giannisp/git-contrib-calendar) - Display a contributions calendar for any git repository.
122- [gitgud](https://github.com/GitGud-org/GitGud) - An interactive command-line GUI for Git.
123- [Autarky](https://github.com/pranshuchittora/autarky) - Find and delete old `node_modules` directories in order to free up disk space.
124- [fast-cli](https://github.com/sindresorhus/fast-cli) - Test your download and upload speed.
125- [tasuku](https://github.com/privatenumber/tasuku) - Minimal task runner.
126- [mnswpr](https://github.com/mordv/mnswpr) - Minesweeper game.
127- [lrn](https://github.com/krychu/lrn) - Learning by repetition.
128- [turdle](https://github.com/mynameisankit/turdle) - Wordle game.
129- [Shopify CLI](https://github.com/Shopify/cli) - Build apps, themes, and storefronts for Shopify.
130- [ToDesktop CLI](https://www.todesktop.com/electron) - An all-in-one platform for building Electron apps.
131
132## Contents
133
134- [Getting Started](#getting-started)
135- [Components](#components)
136 - [`<Text>`](#text)
137 - [`<Box>`](#box)
138 - [`<Newline>`](#newline)
139 - [`<Spacer>`](#spacer)
140 - [`<Static>`](#static)
141 - [`<Transform>`](#transform)
142- [Hooks](#hooks)
143 - [`useInput`](#useinputinputhandler-options)
144 - [`useApp`](#useapp)
145 - [`useStdin`](#usestdin)
146 - [`useStdout`](#usestdout)
147 - [`useStderr`](#usestderr)
148 - [`useFocus`](#usefocusoptions)
149 - [`useFocusManager`](#usefocusmanager)
150- [API](#api)
151- [Testing](#testing)
152- [Using React Devtools](#using-react-devtools)
153- [Useful Components](#useful-components)
154- [Useful Hooks](#useful-hooks)
155- [Examples](#examples)
156
157## Getting Started
158
159Use [create-ink-app](https://github.com/vadimdemedes/create-ink-app) to quickly scaffold a new Ink-based CLI.
160
161```sh
162npx create-ink-app my-ink-cli
163```
164
165Alternatively, create a TypeScript project:
166
167```sh
168npx create-ink-app --typescript my-ink-cli
169```
170
171<details><summary>Manual setup</summary>
172<p>
173Ink requires the same Babel setup as you would do for regular React-based apps in the browser.
174
175Set up Babel with a React preset to ensure all examples in this readme work as expected.
176After [installing Babel](https://babeljs.io/docs/en/usage), install `@babel/preset-react` and insert the following configuration in `babel.config.json`:
177
178```sh
179npm install --save-dev @babel/preset-react
180```
181
182```json
183{
184 "presets": [
185 "@babel/preset-react",
186 [
187 "@babel/preset-env",
188 {
189 "targets": {
190 "node": true
191 }
192 }
193 ]
194 ]
195}
196```
197
198Next, create a file `source.js`, where you'll type code that uses Ink:
199
200```jsx
201import React from 'react';
202import {render, Text} from 'ink';
203
204const Demo = () => <Text>Hello World</Text>;
205
206render(<Demo />);
207```
208
209Then, transpile this file with Babel:
210
211```sh
212npx babel source.js -o cli.js
213```
214
215Now you can run `cli.js` with Node.js:
216
217```sh
218node cli
219```
220
221If you don't like transpiling files during development, you can use [import-jsx](https://github.com/vadimdemedes/import-jsx) or [@esbuild-kit/esm-loader](https://github.com/esbuild-kit/esm-loader) to `import` a JSX file and transpile it on the fly.
222
223</p>
224</details>
225
226Ink uses [Yoga](https://github.com/facebook/yoga) - a Flexbox layout engine to build great user interfaces for your CLIs using familiar CSS-like props you've used when building apps for the browser.
227It's important to remember that each element is a Flexbox container.
228Think of it as if each `<div>` in the browser had `display: flex`.
229See [`<Box>`](#box) built-in component below for documentation on how to use Flexbox layouts in Ink.
230Note that all text must be wrapped in a [`<Text>`](#text) component.
231
232## Components
233
234### `<Text>`
235
236This component can display text, and change its style to make it bold, underline, italic or strikethrough.
237
238```jsx
239import {render, Text} from 'ink';
240
241const Example = () => (
242 <>
243 <Text color="green">I am green</Text>
244 <Text color="black" backgroundColor="white">
245 I am black on white
246 </Text>
247 <Text color="#ffffff">I am white</Text>
248 <Text bold>I am bold</Text>
249 <Text italic>I am italic</Text>
250 <Text underline>I am underline</Text>
251 <Text strikethrough>I am strikethrough</Text>
252 <Text inverse>I am inversed</Text>
253 </>
254);
255
256render(<Example />);
257```
258
259**Note:** `<Text>` allows only text nodes and nested `<Text>` components inside of it. For example, `<Box>` component can't be used inside `<Text>`.
260
261#### color
262
263Type: `string`
264
265Change text color.
266Ink uses [chalk](https://github.com/chalk/chalk) under the hood, so all its functionality is supported.
267
268```jsx
269<Text color="green">Green</Text>
270<Text color="#005cc5">Blue</Text>
271<Text color="rgb(232, 131, 136)">Red</Text>
272```
273
274<img src="media/text-color.jpg" width="247">
275
276#### backgroundColor
277
278Type: `string`
279
280Same as `color` above, but for background.
281
282```jsx
283<Text backgroundColor="green" color="white">Green</Text>
284<Text backgroundColor="#005cc5" color="white">Blue</Text>
285<Text backgroundColor="rgb(232, 131, 136)" color="white">Red</Text>
286```
287
288<img src="media/text-backgroundColor.jpg" width="226">
289
290#### dimColor
291
292Type: `boolean`\
293Default: `false`
294
295Dim the color (emit a small amount of light).
296
297```jsx
298<Text color="red" dimColor>
299 Dimmed Red
300</Text>
301```
302
303<img src="media/text-dimColor.jpg" width="138">
304
305#### bold
306
307Type: `boolean`\
308Default: `false`
309
310Make the text bold.
311
312#### italic
313
314Type: `boolean`\
315Default: `false`
316
317Make the text italic.
318
319#### underline
320
321Type: `boolean`\
322Default: `false`
323
324Make the text underlined.
325
326#### strikethrough
327
328Type: `boolean`\
329Default: `false`
330
331Make the text crossed with a line.
332
333#### inverse
334
335Type: `boolean`\
336Default: `false`
337
338Inverse background and foreground colors.
339
340```jsx
341<Text inverse color="yellow">
342 Inversed Yellow
343</Text>
344```
345
346<img src="media/text-inverse.jpg" width="138">
347
348#### wrap
349
350Type: `string`\
351Allowed values: `wrap` `truncate` `truncate-start` `truncate-middle` `truncate-end`\
352Default: `wrap`
353
354This property tells Ink to wrap or truncate text if its width is larger than container.
355If `wrap` is passed (by default), Ink will wrap text and split it into multiple lines.
356If `truncate-*` is passed, Ink will truncate text instead, which will result in one line of text with the rest cut off.
357
358```jsx
359<Box width={7}>
360 <Text>Hello World</Text>
361</Box>
362//=> 'Hello\nWorld'
363
364// `truncate` is an alias to `truncate-end`
365<Box width={7}>
366 <Text wrap="truncate">Hello World</Text>
367</Box>
368//=> 'Hello…'
369
370<Box width={7}>
371 <Text wrap="truncate-middle">Hello World</Text>
372</Box>
373//=> 'He…ld'
374
375<Box width={7}>
376 <Text wrap="truncate-start">Hello World</Text>
377</Box>
378//=> '…World'
379```
380
381### `<Box>`
382
383`<Box>` is an essential Ink component to build your layout.
384It's like `<div style="display: flex">` in the browser.
385
386```jsx
387import {render, Box, Text} from 'ink';
388
389const Example = () => (
390 <Box margin={2}>
391 <Text>This is a box with margin</Text>
392 </Box>
393);
394
395render(<Example />);
396```
397
398#### Dimensions
399
400##### width
401
402Type: `number` `string`
403
404Width of the element in spaces.
405You can also set it in percent, which will calculate the width based on the width of parent element.
406
407```jsx
408<Box width={4}>
409 <Text>X</Text>
410</Box>
411//=> 'X '
412```
413
414```jsx
415<Box width={10}>
416 <Box width="50%">
417 <Text>X</Text>
418 </Box>
419 <Text>Y</Text>
420</Box>
421//=> 'X Y'
422```
423
424##### height
425
426Type: `number` `string`
427
428Height of the element in lines (rows).
429You can also set it in percent, which will calculate the height based on the height of parent element.
430
431```jsx
432<Box height={4}>
433 <Text>X</Text>
434</Box>
435//=> 'X\n\n\n'
436```
437
438```jsx
439<Box height={6} flexDirection="column">
440 <Box height="50%">
441 <Text>X</Text>
442 </Box>
443 <Text>Y</Text>
444</Box>
445//=> 'X\n\n\nY\n\n'
446```
447
448##### minWidth
449
450Type: `number`
451
452Sets a minimum width of the element.
453Percentages aren't supported yet, see https://github.com/facebook/yoga/issues/872.
454
455##### minHeight
456
457Type: `number`
458
459Sets a minimum height of the element.
460Percentages aren't supported yet, see https://github.com/facebook/yoga/issues/872.
461
462#### Padding
463
464##### paddingTop
465
466Type: `number`\
467Default: `0`
468
469Top padding.
470
471##### paddingBottom
472
473Type: `number`\
474Default: `0`
475
476Bottom padding.
477
478##### paddingLeft
479
480Type: `number`\
481Default: `0`
482
483Left padding.
484
485##### paddingRight
486
487Type: `number`\
488Default: `0`
489
490Right padding.
491
492##### paddingX
493
494Type: `number`\
495Default: `0`
496
497Horizontal padding. Equivalent to setting `paddingLeft` and `paddingRight`.
498
499##### paddingY
500
501Type: `number`\
502Default: `0`
503
504Vertical padding. Equivalent to setting `paddingTop` and `paddingBottom`.
505
506##### padding
507
508Type: `number`\
509Default: `0`
510
511Padding on all sides. Equivalent to setting `paddingTop`, `paddingBottom`, `paddingLeft` and `paddingRight`.
512
513```jsx
514<Box paddingTop={2}>Top</Box>
515<Box paddingBottom={2}>Bottom</Box>
516<Box paddingLeft={2}>Left</Box>
517<Box paddingRight={2}>Right</Box>
518<Box paddingX={2}>Left and right</Box>
519<Box paddingY={2}>Top and bottom</Box>
520<Box padding={2}>Top, bottom, left and right</Box>
521```
522
523#### Margin
524
525##### marginTop
526
527Type: `number`\
528Default: `0`
529
530Top margin.
531
532##### marginBottom
533
534Type: `number`\
535Default: `0`
536
537Bottom margin.
538
539##### marginLeft
540
541Type: `number`\
542Default: `0`
543
544Left margin.
545
546##### marginRight
547
548Type: `number`\
549Default: `0`
550
551Right margin.
552
553##### marginX
554
555Type: `number`\
556Default: `0`
557
558Horizontal margin. Equivalent to setting `marginLeft` and `marginRight`.
559
560##### marginY
561
562Type: `number`\
563Default: `0`
564
565Vertical margin. Equivalent to setting `marginTop` and `marginBottom`.
566
567##### margin
568
569Type: `number`\
570Default: `0`
571
572Margin on all sides. Equivalent to setting `marginTop`, `marginBottom`, `marginLeft` and `marginRight`.
573
574```jsx
575<Box marginTop={2}>Top</Box>
576<Box marginBottom={2}>Bottom</Box>
577<Box marginLeft={2}>Left</Box>
578<Box marginRight={2}>Right</Box>
579<Box marginX={2}>Left and right</Box>
580<Box marginY={2}>Top and bottom</Box>
581<Box margin={2}>Top, bottom, left and right</Box>
582```
583
584#### Gap
585
586#### gap
587
588Type: `number`\
589Default: `0`
590
591Size of the gap between an element's columns and rows. Shorthand for `columnGap` and `rowGap`.
592
593```jsx
594<Box gap={1} width={3} flexWrap="wrap">
595 <Text>A</Text>
596 <Text>B</Text>
597 <Text>C</Text>
598</Box>
599// A B
600//
601// C
602```
603
604#### columnGap
605
606Type: `number`\
607Default: `0`
608
609Size of the gap between an element's columns.
610
611```jsx
612<Box gap={1}>
613 <Text>A</Text>
614 <Text>B</Text>
615</Box>
616// A B
617```
618
619#### rowGap
620
621Type: `number`\
622Default: `0`
623
624Size of the gap between element's rows.
625
626```jsx
627<Box flexDirection="column" gap={1}>
628 <Text>A</Text>
629 <Text>B</Text>
630</Box>
631// A
632//
633// B
634```
635
636#### Flex
637
638##### flexGrow
639
640Type: `number`\
641Default: `0`
642
643See [flex-grow](https://css-tricks.com/almanac/properties/f/flex-grow/).
644
645```jsx
646<Box>
647 <Text>Label:</Text>
648 <Box flexGrow={1}>
649 <Text>Fills all remaining space</Text>
650 </Box>
651</Box>
652```
653
654##### flexShrink
655
656Type: `number`\
657Default: `1`
658
659See [flex-shrink](https://css-tricks.com/almanac/properties/f/flex-shrink/).
660
661```jsx
662<Box width={20}>
663 <Box flexShrink={2} width={10}>
664 <Text>Will be 1/4</Text>
665 </Box>
666 <Box width={10}>
667 <Text>Will be 3/4</Text>
668 </Box>
669</Box>
670```
671
672##### flexBasis
673
674Type: `number` `string`
675
676See [flex-basis](https://css-tricks.com/almanac/properties/f/flex-basis/).
677
678```jsx
679<Box width={6}>
680 <Box flexBasis={3}>
681 <Text>X</Text>
682 </Box>
683 <Text>Y</Text>
684</Box>
685//=> 'X Y'
686```
687
688```jsx
689<Box width={6}>
690 <Box flexBasis="50%">
691 <Text>X</Text>
692 </Box>
693 <Text>Y</Text>
694</Box>
695//=> 'X Y'
696```
697
698##### flexDirection
699
700Type: `string`\
701Allowed values: `row` `row-reverse` `column` `column-reverse`
702
703See [flex-direction](https://css-tricks.com/almanac/properties/f/flex-direction/).
704
705```jsx
706<Box>
707 <Box marginRight={1}>
708 <Text>X</Text>
709 </Box>
710 <Text>Y</Text>
711</Box>
712// X Y
713
714<Box flexDirection="row-reverse">
715 <Text>X</Text>
716 <Box marginRight={1}>
717 <Text>Y</Text>
718 </Box>
719</Box>
720// Y X
721
722<Box flexDirection="column">
723 <Text>X</Text>
724 <Text>Y</Text>
725</Box>
726// X
727// Y
728
729<Box flexDirection="column-reverse">
730 <Text>X</Text>
731 <Text>Y</Text>
732</Box>
733// Y
734// X
735```
736
737##### flexWrap
738
739Type: `string`\
740Allowed values: `nowrap` `wrap` `wrap-reverse`
741
742See [flex-wrap](https://css-tricks.com/almanac/properties/f/flex-wrap/).
743
744```jsx
745<Box width={2} flexWrap="wrap">
746 <Text>A</Text>
747 <Text>BC</Text>
748</Box>
749// A
750// B C
751```
752
753```jsx
754<Box flexDirection="column" height={2} flexWrap="wrap">
755 <Text>A</Text>
756 <Text>B</Text>
757 <Text>C</Text>
758</Box>
759// A C
760// B
761```
762
763##### alignItems
764
765Type: `string`\
766Allowed values: `flex-start` `center` `flex-end`
767
768See [align-items](https://css-tricks.com/almanac/properties/a/align-items/).
769
770```jsx
771<Box alignItems="flex-start">
772 <Box marginRight={1}>
773 <Text>X</Text>
774 </Box>
775 <Text>
776 A
777 <Newline/>
778 B
779 <Newline/>
780 C
781 </Text>
782</Box>
783// X A
784// B
785// C
786
787<Box alignItems="center">
788 <Box marginRight={1}>
789 <Text>X</Text>
790 </Box>
791 <Text>
792 A
793 <Newline/>
794 B
795 <Newline/>
796 C
797 </Text>
798</Box>
799// A
800// X B
801// C
802
803<Box alignItems="flex-end">
804 <Box marginRight={1}>
805 <Text>X</Text>
806 </Box>
807 <Text>
808 A
809 <Newline/>
810 B
811 <Newline/>
812 C
813 </Text>
814</Box>
815// A
816// B
817// X C
818```
819
820##### alignSelf
821
822Type: `string`\
823Default: `auto`\
824Allowed values: `auto` `flex-start` `center` `flex-end`
825
826See [align-self](https://css-tricks.com/almanac/properties/a/align-self/).
827
828```jsx
829<Box height={3}>
830 <Box alignSelf="flex-start">
831 <Text>X</Text>
832 </Box>
833</Box>
834// X
835//
836//
837
838<Box height={3}>
839 <Box alignSelf="center">
840 <Text>X</Text>
841 </Box>
842</Box>
843//
844// X
845//
846
847<Box height={3}>
848 <Box alignSelf="flex-end">
849 <Text>X</Text>
850 </Box>
851</Box>
852//
853//
854// X
855```
856
857##### justifyContent
858
859Type: `string`\
860Allowed values: `flex-start` `center` `flex-end` `space-between` `space-around`
861
862See [justify-content](https://css-tricks.com/almanac/properties/j/justify-content/).
863
864```jsx
865<Box justifyContent="flex-start">
866 <Text>X</Text>
867</Box>
868// [X ]
869
870<Box justifyContent="center">
871 <Text>X</Text>
872</Box>
873// [ X ]
874
875<Box justifyContent="flex-end">
876 <Text>X</Text>
877</Box>
878// [ X]
879
880<Box justifyContent="space-between">
881 <Text>X</Text>
882 <Text>Y</Text>
883</Box>
884// [X Y]
885
886<Box justifyContent="space-around">
887 <Text>X</Text>
888 <Text>Y</Text>
889</Box>
890// [ X Y ]
891```
892
893#### Visibility
894
895##### display
896
897Type: `string`\
898Allowed values: `flex` `none`\
899Default: `flex`
900
901Set this property to `none` to hide the element.
902
903##### overflowX
904
905Type: `string`\
906Allowed values: `visible` `hidden`\
907Default: `visible`
908
909Behavior for an element's overflow in horizontal direction.
910
911##### overflowY
912
913Type: `string`\
914Allowed values: `visible` `hidden`\
915Default: `visible`
916
917Behavior for an element's overflow in vertical direction.
918
919##### overflow
920
921Type: `string`\
922Allowed values: `visible` `hidden`\
923Default: `visible`
924
925Shortcut for setting `overflowX` and `overflowY` at the same time.
926
927#### Borders
928
929##### borderStyle
930
931Type: `string`\
932Allowed values: `single` `double` `round` `bold` `singleDouble` `doubleSingle` `classic`
933
934Add a border with a specified style.
935If `borderStyle` is `undefined` (which it is by default), no border will be added.
936Ink uses border styles from [`cli-boxes`](https://github.com/sindresorhus/cli-boxes) module.
937
938```jsx
939<Box flexDirection="column">
940 <Box>
941 <Box borderStyle="single" marginRight={2}>
942 <Text>single</Text>
943 </Box>
944
945 <Box borderStyle="double" marginRight={2}>
946 <Text>double</Text>
947 </Box>
948
949 <Box borderStyle="round" marginRight={2}>
950 <Text>round</Text>
951 </Box>
952
953 <Box borderStyle="bold">
954 <Text>bold</Text>
955 </Box>
956 </Box>
957
958 <Box marginTop={1}>
959 <Box borderStyle="singleDouble" marginRight={2}>
960 <Text>singleDouble</Text>
961 </Box>
962
963 <Box borderStyle="doubleSingle" marginRight={2}>
964 <Text>doubleSingle</Text>
965 </Box>
966
967 <Box borderStyle="classic">
968 <Text>classic</Text>
969 </Box>
970 </Box>
971</Box>
972```
973
974<img src="media/box-borderStyle.jpg" width="521">
975
976See example in [examples/borders](examples/borders/borders.js).
977
978##### borderColor
979
980Type: `string`
981
982Change border color.
983Accepts the same values as [`color`](#color) in `<Text>` component.
984
985```jsx
986<Box borderStyle="round" borderColor="green">
987 <Text>Green Rounded Box</Text>
988</Box>
989```
990
991<img src="media/box-borderColor.jpg" width="228">
992
993### `<Newline>`
994
995Adds one or more newline (`\n`) characters.
996Must be used within `<Text>` components.
997
998#### count
999
1000Type: `number`\
1001Default: `1`
1002
1003Number of newlines to insert.
1004
1005```jsx
1006import {render, Text, Newline} from 'ink';
1007
1008const Example = () => (
1009 <Text>
1010 <Text color="green">Hello</Text>
1011 <Newline />
1012 <Text color="red">World</Text>
1013 </Text>
1014);
1015
1016render(<Example />);
1017```
1018
1019Output:
1020
1021```
1022Hello
1023World
1024```
1025
1026### `<Spacer>`
1027
1028A flexible space that expands along the major axis of its containing layout.
1029It's useful as a shortcut for filling all the available spaces between elements.
1030
1031For example, using `<Spacer>` in a `<Box>` with default flex direction (`row`) will position "Left" on the left side and will push "Right" to the right side.
1032
1033```jsx
1034import {render, Box, Text, Spacer} from 'ink';
1035
1036const Example = () => (
1037 <Box>
1038 <Text>Left</Text>
1039 <Spacer />
1040 <Text>Right</Text>
1041 </Box>
1042);
1043
1044render(<Example />);
1045```
1046
1047In a vertical flex direction (`column`), it will position "Top" to the top of the container and push "Bottom" to the bottom of it.
1048Note, that container needs to be tall to enough to see this in effect.
1049
1050```jsx
1051import {render, Box, Text, Spacer} from 'ink';
1052
1053const Example = () => (
1054 <Box flexDirection="column" height={10}>
1055 <Text>Top</Text>
1056 <Spacer />
1057 <Text>Bottom</Text>
1058 </Box>
1059);
1060
1061render(<Example />);
1062```
1063
1064### `<Static>`
1065
1066`<Static>` component permanently renders its output above everything else.
1067It's useful for displaying activity like completed tasks or logs - things that
1068are not changing after they're rendered (hence the name "Static").
1069
1070It's preferred to use `<Static>` for use cases like these, when you can't know
1071or control the amount of items that need to be rendered.
1072
1073For example, [Tap](https://github.com/tapjs/node-tap) uses `<Static>` to display
1074a list of completed tests. [Gatsby](https://github.com/gatsbyjs/gatsby) uses it
1075to display a list of generated pages, while still displaying a live progress bar.
1076
1077```jsx
1078import React, {useState, useEffect} from 'react';
1079import {render, Static, Box, Text} from 'ink';
1080
1081const Example = () => {
1082 const [tests, setTests] = useState([]);
1083
1084 useEffect(() => {
1085 let completedTests = 0;
1086 let timer;
1087
1088 const run = () => {
1089 // Fake 10 completed tests
1090 if (completedTests++ < 10) {
1091 setTests(previousTests => [
1092 ...previousTests,
1093 {
1094 id: previousTests.length,
1095 title: `Test #${previousTests.length + 1}`
1096 }
1097 ]);
1098
1099 setTimeout(run, 100);
1100 }
1101 };
1102
1103 run();
1104
1105 return () => {
1106 clearTimeout(timer);
1107 };
1108 }, []);
1109
1110 return (
1111 <>
1112 {/* This part will be rendered once to the terminal */}
1113 <Static items={tests}>
1114 {test => (
1115 <Box key={test.id}>
1116 <Text color="green">✔ {test.title}</Text>
1117 </Box>
1118 )}
1119 </Static>
1120
1121 {/* This part keeps updating as state changes */}
1122 <Box marginTop={1}>
1123 <Text dimColor>Completed tests: {tests.length}</Text>
1124 </Box>
1125 </>
1126 );
1127};
1128
1129render(<Example />);
1130```
1131
1132**Note:** `<Static>` only renders new items in `items` prop and ignores items
1133that were previously rendered. This means that when you add new items to `items`
1134array, changes you make to previous items will not trigger a rerender.
1135
1136See [examples/static](examples/static/static.js) for an example usage of `<Static>` component.
1137
1138#### items
1139
1140Type: `Array`
1141
1142Array of items of any type to render using a function you pass as a component child.
1143
1144#### style
1145
1146Type: `object`
1147
1148Styles to apply to a container of child elements.
1149See [`<Box>`](#box) for supported properties.
1150
1151```jsx
1152<Static items={...} style={{padding: 1}}>
1153 {...}
1154</Static>
1155```
1156
1157#### children(item)
1158
1159Type: `Function`
1160
1161Function that is called to render every item in `items` array.
1162First argument is an item itself and second argument is index of that item in
1163`items` array.
1164
1165Note that `key` must be assigned to the root component.
1166
1167```jsx
1168<Static items={['a', 'b', 'c']}>
1169 {(item, index) => {
1170 // This function is called for every item in ['a', 'b', 'c']
1171 // `item` is 'a', 'b', 'c'
1172 // `index` is 0, 1, 2
1173 return (
1174 <Box key={index}>
1175 <Text>Item: {item}</Text>
1176 </Box>
1177 );
1178 }}
1179</Static>
1180```
1181
1182### `<Transform>`
1183
1184Transform a string representation of React components before they are written to output.
1185For example, you might want to apply a [gradient to text](https://github.com/sindresorhus/ink-gradient), [add a clickable link](https://github.com/sindresorhus/ink-link) or [create some text effects](https://github.com/sindresorhus/ink-big-text).
1186These use cases can't accept React nodes as input, they are expecting a string.
1187That's what `<Transform>` component does, it gives you an output string of its child components and lets you transform it in any way.
1188
1189**Note:** `<Transform>` must be applied only to `<Text>` children components and shouldn't change the dimensions of the output, otherwise layout will be incorrect.
1190
1191```jsx
1192import {render, Transform} from 'ink';
1193
1194const Example = () => (
1195 <Transform transform={output => output.toUpperCase()}>
1196 <Text>Hello World</Text>
1197 </Transform>
1198);
1199
1200render(<Example />);
1201```
1202
1203Since `transform` function converts all characters to upper case, final output that's rendered to the terminal will be "HELLO WORLD", not "Hello World".
1204
1205#### transform(children)
1206
1207Type: `Function`
1208
1209Function which transforms children output.
1210It accepts children and must return transformed children too.
1211
1212##### children
1213
1214Type: `string`
1215
1216Output of child components.
1217
1218## Hooks
1219
1220### useInput(inputHandler, options?)
1221
1222This hook is used for handling user input.
1223It's a more convenient alternative to using `useStdin` and listening to `data` events.
1224The callback you pass to `useInput` is called for each character when user enters any input.
1225However, if user pastes text and it's more than one character, the callback will be called only once and the whole string will be passed as `input`.
1226You can find a full example of using `useInput` at [examples/use-input](examples/use-input/use-input.js).
1227
1228```jsx
1229import {useInput} from 'ink';
1230
1231const UserInput = () => {
1232 useInput((input, key) => {
1233 if (input === 'q') {
1234 // Exit program
1235 }
1236
1237 if (key.leftArrow) {
1238 // Left arrow key pressed
1239 }
1240 });
1241
1242 return …
1243};
1244```
1245
1246#### inputHandler(input, key)
1247
1248Type: `Function`
1249
1250The handler function that you pass to `useInput` receives two arguments:
1251
1252##### input
1253
1254Type: `string`
1255
1256The input that the program received.
1257
1258##### key
1259
1260Type: `object`
1261
1262Handy information about a key that was pressed.
1263
1264###### key.leftArrow
1265
1266###### key.rightArrow
1267
1268###### key.upArrow
1269
1270###### key.downArrow
1271
1272Type: `boolean`\
1273Default: `false`
1274
1275If an arrow key was pressed, the corresponding property will be `true`.
1276For example, if user presses left arrow key, `key.leftArrow` equals `true`.
1277
1278###### key.return
1279
1280Type: `boolean`\
1281Default: `false`
1282
1283Return (Enter) key was pressed.
1284
1285###### key.escape
1286
1287Type: `boolean`\
1288Default: `false`
1289
1290Escape key was pressed.
1291
1292###### key.ctrl
1293
1294Type: `boolean`\
1295Default: `false`
1296
1297Ctrl key was pressed.
1298
1299###### key.shift
1300
1301Type: `boolean`\
1302Default: `false`
1303
1304Shift key was pressed.
1305
1306###### key.tab
1307
1308Type: `boolean`\
1309Default: `false`
1310
1311Tab key was pressed.
1312
1313###### key.backspace
1314
1315Type: `boolean`\
1316Default: `false`
1317
1318Backspace key was pressed.
1319
1320###### key.delete
1321
1322Type: `boolean`\
1323Default: `false`
1324
1325Delete key was pressed.
1326
1327###### key.pageDown
1328
1329###### key.pageUp
1330
1331Type: `boolean`\
1332Default: `false`
1333
1334If Page Up or Page Down key was pressed, the corresponding property will be `true`.
1335For example, if user presses Page Down, `key.pageDown` equals `true`.
1336
1337###### key.meta
1338
1339Type: `boolean`\
1340Default: `false`
1341
1342[Meta key](https://en.wikipedia.org/wiki/Meta_key) was pressed.
1343
1344#### options
1345
1346Type: `object`
1347
1348##### isActive
1349
1350Type: `boolean`\
1351Default: `true`
1352
1353Enable or disable capturing of user input.
1354Useful when there are multiple `useInput` hooks used at once to avoid handling the same input several times.
1355
1356### useApp()
1357
1358`useApp` is a React hook, which exposes a method to manually exit the app (unmount).
1359
1360#### exit(error?)
1361
1362Type: `Function`
1363
1364Exit (unmount) the whole Ink app.
1365
1366##### error
1367
1368Type: `Error`
1369
1370Optional error. If passed, [`waitUntilExit`](waituntilexit) will reject with that error.
1371
1372```js
1373import {useApp} from 'ink';
1374
1375const Example = () => {
1376 const {exit} = useApp();
1377
1378 // Exit the app after 5 seconds
1379 useEffect(() => {
1380 setTimeout(() => {
1381 exit();
1382 }, 5000);
1383 }, []);
1384
1385 return …
1386};
1387```
1388
1389### useStdin()
1390
1391`useStdin` is a React hook, which exposes stdin stream.
1392
1393#### stdin
1394
1395Type: `stream.Readable`\
1396Default: `process.stdin`
1397
1398Stdin stream passed to `render()` in `options.stdin` or `process.stdin` by default.
1399Useful if your app needs to handle user input.
1400
1401```js
1402import {useStdin} from 'ink';
1403
1404const Example = () => {
1405 const {stdin} = useStdin();
1406
1407 return …
1408};
1409```
1410
1411#### isRawModeSupported
1412
1413Type: `boolean`
1414
1415A boolean flag determining if the current `stdin` supports `setRawMode`.
1416A component using `setRawMode` might want to use `isRawModeSupported` to nicely fall back in environments where raw mode is not supported.
1417
1418```jsx
1419import {useStdin} from 'ink';
1420
1421const Example = () => {
1422 const {isRawModeSupported} = useStdin();
1423
1424 return isRawModeSupported ? (
1425 <MyInputComponent />
1426 ) : (
1427 <MyComponentThatDoesntUseInput />
1428 );
1429};
1430```
1431
1432#### setRawMode(isRawModeEnabled)
1433
1434Type: `function`
1435
1436##### isRawModeEnabled
1437
1438Type: `boolean`
1439
1440See [`setRawMode`](https://nodejs.org/api/tty.html#tty_readstream_setrawmode_mode).
1441Ink exposes this function to be able to handle <kbd>Ctrl</kbd>+<kbd>C</kbd>, that's why you should use Ink's `setRawMode` instead of `process.stdin.setRawMode`.
1442
1443**Warning:** This function will throw unless the current `stdin` supports `setRawMode`. Use [`isRawModeSupported`](#israwmodesupported) to detect `setRawMode` support.
1444
1445```js
1446import {useStdin} from 'ink';
1447
1448const Example = () => {
1449 const {setRawMode} = useStdin();
1450
1451 useEffect(() => {
1452 setRawMode(true);
1453
1454 return () => {
1455 setRawMode(false);
1456 };
1457 });
1458
1459 return …
1460};
1461```
1462
1463### useStdout()
1464
1465`useStdout` is a React hook, which exposes stdout stream, where Ink renders your app.
1466
1467#### stdout
1468
1469Type: `stream.Writable`\
1470Default: `process.stdout`
1471
1472```js
1473import {useStdout} from 'ink';
1474
1475const Example = () => {
1476 const {stdout} = useStdout();
1477
1478 return …
1479};
1480```
1481
1482#### write(data)
1483
1484Write any string to stdout, while preserving Ink's output.
1485It's useful when you want to display some external information outside of Ink's rendering and ensure there's no conflict between the two.
1486It's similar to `<Static>`, except it can't accept components, it only works with strings.
1487
1488##### data
1489
1490Type: `string`
1491
1492Data to write to stdout.
1493
1494```js
1495import {useStdout} from 'ink';
1496
1497const Example = () => {
1498 const {write} = useStdout();
1499
1500 useEffect(() => {
1501 // Write a single message to stdout, above Ink's output
1502 write('Hello from Ink to stdout\n');
1503 }, []);
1504
1505 return …
1506};
1507```
1508
1509See additional usage example in [examples/use-stdout](examples/use-stdout/use-stdout.js).
1510
1511### useStderr()
1512
1513`useStderr` is a React hook, which exposes stderr stream.
1514
1515#### stderr
1516
1517Type: `stream.Writable`\
1518Default: `process.stderr`
1519
1520Stderr stream.
1521
1522```js
1523import {useStderr} from 'ink';
1524
1525const Example = () => {
1526 const {stderr} = useStderr();
1527
1528 return …
1529};
1530```
1531
1532#### write(data)
1533
1534Write any string to stderr, while preserving Ink's output.
1535
1536It's useful when you want to display some external information outside of Ink's rendering and ensure there's no conflict between the two.
1537It's similar to `<Static>`, except it can't accept components, it only works with strings.
1538
1539##### data
1540
1541Type: `string`
1542
1543Data to write to stderr.
1544
1545```js
1546import {useStderr} from 'ink';
1547
1548const Example = () => {
1549 const {write} = useStderr();
1550
1551 useEffect(() => {
1552 // Write a single message to stderr, above Ink's output
1553 write('Hello from Ink to stderr\n');
1554 }, []);
1555
1556 return …
1557};
1558```
1559
1560### useFocus(options?)
1561
1562Component that uses `useFocus` hook becomes "focusable" to Ink, so when user presses <kbd>Tab</kbd>, Ink will switch focus to this component.
1563If there are multiple components that execute `useFocus` hook, focus will be given to them in the order that these components are rendered in.
1564This hook returns an object with `isFocused` boolean property, which determines if this component is focused or not.
1565
1566#### options
1567
1568##### autoFocus
1569
1570Type: `boolean`\
1571Default: `false`
1572
1573Auto focus this component, if there's no active (focused) component right now.
1574
1575##### isActive
1576
1577Type: `boolean`\
1578Default: `true`
1579
1580Enable or disable this component's focus, while still maintaining its position in the list of focusable components.
1581This is useful for inputs that are temporarily disabled.
1582
1583##### id
1584
1585Type: `string`\
1586Required: `false`
1587
1588Set a component's focus ID, which can be used to programmatically focus the component. This is useful for large interfaces with many focusable elements, to avoid having to cycle through all of them.
1589
1590```jsx
1591import {render, useFocus, Text} from 'ink';
1592
1593const Example = () => {
1594 const {isFocused} = useFocus();
1595
1596 return <Text>{isFocused ? 'I am focused' : 'I am not focused'}</Text>;
1597};
1598
1599render(<Example />);
1600```
1601
1602See example in [examples/use-focus](examples/use-focus/use-focus.js) and [examples/use-focus-with-id](examples/use-focus-with-id/use-focus-with-id.js).
1603
1604### useFocusManager()
1605
1606This hook exposes methods to enable or disable focus management for all components or manually switch focus to next or previous components.
1607
1608#### enableFocus()
1609
1610Enable focus management for all components.
1611
1612**Note:** You don't need to call this method manually, unless you've disabled focus management. Focus management is enabled by default.
1613
1614```js
1615import {useFocusManager} from 'ink';
1616
1617const Example = () => {
1618 const {enableFocus} = useFocusManager();
1619
1620 useEffect(() => {
1621 enableFocus();
1622 }, []);
1623
1624 return …
1625};
1626```
1627
1628#### disableFocus()
1629
1630Disable focus management for all components.
1631Currently active component (if there's one) will lose its focus.
1632
1633```js
1634import {useFocusManager} from 'ink';
1635
1636const Example = () => {
1637 const {disableFocus} = useFocusManager();
1638
1639 useEffect(() => {
1640 disableFocus();
1641 }, []);
1642
1643 return …
1644};
1645```
1646
1647#### focusNext()
1648
1649Switch focus to the next focusable component.
1650If there's no active component right now, focus will be given to the first focusable component.
1651If active component is the last in the list of focusable components, focus will be switched to the first component.
1652
1653**Note:** Ink calls this method when user presses <kbd>Tab</kbd>.
1654
1655```js
1656import {useFocusManager} from 'ink';
1657
1658const Example = () => {
1659 const {focusNext} = useFocusManager();
1660
1661 useEffect(() => {
1662 focusNext();
1663 }, []);
1664
1665 return …
1666};
1667```
1668
1669#### focusPrevious()
1670
1671Switch focus to the previous focusable component.
1672If there's no active component right now, focus will be given to the first focusable component.
1673If active component is the first in the list of focusable components, focus will be switched to the last component.
1674
1675**Note:** Ink calls this method when user presses <kbd>Shift</kbd>+<kbd>Tab</kbd>.
1676
1677```js
1678import {useFocusManager} from 'ink';
1679
1680const Example = () => {
1681 const {focusPrevious} = useFocusManager();
1682
1683 useEffect(() => {
1684 focusPrevious();
1685 }, []);
1686
1687 return …
1688};
1689```
1690
1691#### focus(id)
1692
1693##### id
1694
1695Type: `string`
1696
1697Switch focus to the component with the given [`id`](#id).
1698If there's no component with that ID, focus will be given to the next focusable component.
1699
1700```js
1701import {useFocusManager, useInput} from 'ink';
1702
1703const Example = () => {
1704 const {focus} = useFocusManager();
1705
1706 useInput(input => {
1707 if (input === 's') {
1708 // Focus the component with focus ID 'someId'
1709 focus('someId');
1710 }
1711 });
1712
1713 return …
1714};
1715```
1716
1717## API
1718
1719#### render(tree, options?)
1720
1721Returns: [`Instance`](#instance)
1722
1723Mount a component and render the output.
1724
1725##### tree
1726
1727Type: `ReactElement`
1728
1729##### options
1730
1731Type: `object`
1732
1733###### stdout
1734
1735Type: `stream.Writable`\
1736Default: `process.stdout`
1737
1738Output stream where app will be rendered.
1739
1740###### stdin
1741
1742Type: `stream.Readable`\
1743Default: `process.stdin`
1744
1745Input stream where app will listen for input.
1746
1747###### exitOnCtrlC
1748
1749Type: `boolean`\
1750Default: `true`
1751
1752Configure whether Ink should listen to Ctrl+C keyboard input and exit the app.
1753This is needed in case `process.stdin` is in [raw mode](https://nodejs.org/api/tty.html#tty_readstream_setrawmode_mode), because then Ctrl+C is ignored by default and process is expected to handle it manually.
1754
1755###### patchConsole
1756
1757Type: `boolean`\
1758Default: `true`
1759
1760Patch console methods to ensure console output doesn't mix with Ink output.
1761When any of `console.*` methods are called (like `console.log()`), Ink intercepts their output, clears main output, renders output from the console method and then rerenders main output again.
1762That way both are visible and are not overlapping each other.
1763
1764This functionality is powered by [patch-console](https://github.com/vadimdemedes/patch-console), so if you need to disable Ink's interception of output but want to build something custom, you can use it.
1765
1766###### debug
1767
1768Type: `boolean`\
1769Default: `false`
1770
1771If `true`, each update will be rendered as a separate output, without replacing the previous one.
1772
1773#### Instance
1774
1775This is the object that `render()` returns.
1776
1777##### rerender(tree)
1778
1779Replace previous root node with a new one or update props of the current root node.
1780
1781###### tree
1782
1783Type: `ReactElement`
1784
1785```jsx
1786// Update props of the root node
1787const {rerender} = render(<Counter count={1} />);
1788rerender(<Counter count={2} />);
1789
1790// Replace root node
1791const {rerender} = render(<OldCounter />);
1792rerender(<NewCounter />);
1793```
1794
1795##### unmount()
1796
1797Manually unmount the whole Ink app.
1798
1799```jsx
1800const {unmount} = render(<MyApp />);
1801unmount();
1802```
1803
1804##### waitUntilExit()
1805
1806Returns a promise, which resolves when app is unmounted.
1807
1808```jsx
1809const {unmount, waitUntilExit} = render(<MyApp />);
1810
1811setTimeout(unmount, 1000);
1812
1813await waitUntilExit(); // resolves after `unmount()` is called
1814```
1815
1816##### clear()
1817
1818Clear output.
1819
1820```jsx
1821const {clear} = render(<MyApp />);
1822clear();
1823```
1824
1825#### measureElement(ref)
1826
1827Measure the dimensions of a particular `<Box>` element.
1828It returns an object with `width` and `height` properties.
1829This function is useful when your component needs to know the amount of available space it has. You could use it when you need to change the layout based on the length of its content.
1830
1831**Note:** `measureElement()` returns correct results only after the initial render, when layout has been calculated. Until then, `width` and `height` equal to zero. It's recommended to call `measureElement()` in a `useEffect` hook, which fires after the component has rendered.
1832
1833##### ref
1834
1835Type: `MutableRef`
1836
1837A reference to a `<Box>` element captured with a `ref` property.
1838See [Refs](https://reactjs.org/docs/refs-and-the-dom.html) for more information on how to capture references.
1839
1840```jsx
1841import {render, measureElement, Box, Text} from 'ink';
1842
1843const Example = () => {
1844 const ref = useRef();
1845
1846 useEffect(() => {
1847 const {width, height} = measureElement(ref.current);
1848 // width = 100, height = 1
1849 }, []);
1850
1851 return (
1852 <Box width={100}>
1853 <Box ref={ref}>
1854 <Text>This box will stretch to 100 width</Text>
1855 </Box>
1856 </Box>
1857 );
1858};
1859
1860render(<Example />);
1861```
1862
1863## Testing
1864
1865Ink components are simple to test with [ink-testing-library](https://github.com/vadimdemedes/ink-testing-library).
1866Here's a simple example that checks how component is rendered:
1867
1868```jsx
1869import React from 'react';
1870import {Text} from 'ink';
1871import {render} from 'ink-testing-library';
1872
1873const Test = () => <Text>Hello World</Text>;
1874const {lastFrame} = render(<Test />);
1875
1876lastFrame() === 'Hello World'; //=> true
1877```
1878
1879Check out [ink-testing-library](https://github.com/vadimdemedes/ink-testing-library) for more examples and full documentation.
1880
1881## Using React Devtools
1882
1883![](media/devtools.jpg)
1884
1885Ink supports [React Devtools](https://github.com/facebook/react/tree/master/packages/react-devtools) out-of-the-box.
1886To enable integration with React Devtools in your Ink-based CLI, run it with `DEV=true` environment variable:
1887
1888```sh
1889DEV=true my-cli
1890```
1891
1892Then, start React Devtools itself:
1893
1894```sh
1895npx react-devtools
1896```
1897
1898After it starts up, you should see the component tree of your CLI.
1899You can even inspect and change the props of components, and see the results immediatelly in the CLI, without restarting it.
1900
1901**Note**: You must manually quit your CLI via <kbd>Ctrl</kbd>+<kbd>C</kbd> after you're done testing.
1902
1903## Useful Components
1904
1905- [ink-text-input](https://github.com/vadimdemedes/ink-text-input) - Text input.
1906- [ink-spinner](https://github.com/vadimdemedes/ink-spinner) - Spinner.
1907- [ink-select-input](https://github.com/vadimdemedes/ink-select-input) - Select (dropdown) input.
1908- [ink-link](https://github.com/sindresorhus/ink-link) - Link.
1909- [ink-gradient](https://github.com/sindresorhus/ink-gradient) - Gradient color.
1910- [ink-big-text](https://github.com/sindresorhus/ink-big-text) - Awesome text.
1911- [ink-image](https://github.com/kevva/ink-image) - Display images inside the terminal.
1912- [ink-tab](https://github.com/jdeniau/ink-tab) - Tab.
1913- [ink-color-pipe](https://github.com/LitoMore/ink-color-pipe) - Create color text with simpler style strings.
1914- [ink-multi-select](https://github.com/karaggeorge/ink-multi-select) - Select one or more values from a list
1915- [ink-divider](https://github.com/JureSotosek/ink-divider) - A divider.
1916- [ink-progress-bar](https://github.com/brigand/ink-progress-bar) - Progress bar.
1917- [ink-table](https://github.com/maticzav/ink-table) - Table.
1918- [ink-ascii](https://github.com/hexrcs/ink-ascii) - Awesome text component with more font choices, based on Figlet.
1919- [ink-markdown](https://github.com/cameronhunter/ink-markdown) - Render syntax highlighted Markdown.
1920- [ink-quicksearch-input](https://github.com/Eximchain/ink-quicksearch-input) - Select component with fast quicksearch-like navigation.
1921- [ink-confirm-input](https://github.com/kevva/ink-confirm-input) - Yes/No confirmation input.
1922- [ink-syntax-highlight](https://github.com/vsashyn/ink-syntax-highlight) - Code syntax highlighting.
1923- [ink-form](https://github.com/lukasbach/ink-form) - Form.
1924- [ink-task-list](https://github.com/privatenumber/ink-task-list) - Task list.
1925
1926## Useful Hooks
1927
1928- [ink-use-stdout-dimensions](https://github.com/cameronhunter/ink-monorepo/tree/master/packages/ink-use-stdout-dimensions) - Subscribe to stdout dimensions.
1929
1930## Examples
1931
1932The [`examples`](/examples) directory contains a set of real examples. You can run them with:
1933
1934```bash
1935npm run example examples/[example name]
1936# e.g. npm run example examples/borders
1937```
1938
1939- [Jest](examples/jest/jest.tsx) - Implementation of basic Jest UI [(live demo)](https://ink-jest-demo.vadimdemedes.repl.run/).
1940- [Counter](examples/counter/counter.tsx) - Simple counter that increments every 100ms [(live demo)](https://ink-counter-demo.vadimdemedes.repl.run/).
1941- [Form with validation](https://github.com/final-form/rff-cli-example) - Manage form state using [Final Form](https://github.com/final-form/final-form#-final-form).
1942- [Borders](examples/borders/borders.tsx) - Add borders to `<Box>` component.
1943- [Suspense](examples/suspense/suspense.tsx) - Use React Suspense.
1944- [Table](examples/table/table.tsx) - Render a table with multiple columns and rows.
1945- [Focus management](examples/use-focus/use-focus.tsx) - Use `useFocus` hook to manage focus between components.
1946- [User input](examples/use-input/use-input.tsx) - Listen to user input.
1947- [Write to stdout](examples/use-stdout/use-stdout.tsx) - Write to stdout bypassing main Ink output.
1948- [Write to stderr](examples/use-stderr/use-stderr.tsx) - Write to stderr bypassing main Ink output.
1949- [Static](examples/static/static.tsx) - Use `<Static>` to render permanent output.
1950- [Child process](examples/subprocess-output) - Render output from a child process.
1951
1952## Maintainers
1953
1954- [Vadim Demedes](https://github.com/vadimdemedes)
1955- [Sindre Sorhus](https://github.com/sindresorhus)