UNPKG

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