https://github.com/vadimdemedes/ink-ui
💄 Ink-redible command-line interfaces made easy
https://github.com/vadimdemedes/ink-ui
ink react terminal tui tuikit ui uikit
Last synced: 10 days ago
JSON representation
💄 Ink-redible command-line interfaces made easy
- Host: GitHub
- URL: https://github.com/vadimdemedes/ink-ui
- Owner: vadimdemedes
- License: mit
- Created: 2023-04-27T12:56:48.000Z (about 2 years ago)
- Default Branch: main
- Last Pushed: 2024-05-22T12:20:07.000Z (about 1 year ago)
- Last Synced: 2025-05-10T22:29:23.488Z (13 days ago)
- Topics: ink, react, terminal, tui, tuikit, ui, uikit
- Language: TypeScript
- Homepage: https://term.ink/ui
- Size: 3.38 MB
- Stars: 1,639
- Watchers: 6
- Forks: 17
- Open Issues: 10
-
Metadata Files:
- Readme: readme.md
- License: license
Awesome Lists containing this project
README
[](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)
# Ink UI [](https://github.com/vadimdemedes/ink-ui/actions/workflows/test.yml)
> Collection of customizable UI components for CLIs made with [Ink](https://term.ink).
## Install
```sh
npm install @inkjs/ui
```_This assumes you've already set up [Ink](https://term.ink). The easiest way to get started is [create-ink-app](https://github.com/vadimdemedes/create-ink-app)._
## Components
### Text input
[Documentation](docs/text-input.md)
`TextInput` is used for entering any single-line input with an optional autocomplete.
```jsx
import {TextInput} from '@inkjs/ui';{
// `name` contains user input
}}
/>;
```
### Email input
[Documentation](docs/email-input.md)
`EmailInput` is used for entering an email. After "@" character is entered, domain can be autocompleted from the list of most popular email providers.
```jsx
import {EmailInput} from '@inkjs/ui';{
// `email` contains user input
}}
/>;
```
### Password input
[Documentation](docs/password-input.md)
`PasswordInput` is used for entering sensitive data, like passwords, API keys and so on. It works the same way as `TextInput`, except input value is masked and replaced with asterisks ("\*").
```jsx
import {PasswordInput} from '@inkjs/ui';{
// `password` contains user input
}}
/>;
```
### Confirm input
[Documentation](docs/confirm-input.md)
`ConfirmInput` shows a common "Y/n" input to confirm or cancel an operation your CLI wants to perform.
```jsx
import {ConfirmInput} from '@inkjs/ui';{
// confirmed
}}
onCancel={() => {
// cancelled
}}
/>;
```
### Select
[Documentation](docs/select.md)
`Select` shows a scrollable list of options for a user to choose from.
```jsx
import {Select} from '@inkjs/ui';{
// `newValue` equals the `value` field of the selected option
// For example, "yellow"
}}
/>;
```
### Multi select
[Documentation](docs/multi-select.md)
`MultiSelect` is similar to `Select`, except user can choose multiple options.
```jsx
import {MultiSelect} from '@inkjs/ui';{
// `newValue` is an array of `value` fields of the selected options
// For example, ["green", "yellow"]
}}
/>;
```
### Spinner
[Documentation](docs/spinner.md)
`Spinner` indicates that something is being processed and CLI is waiting for it to complete.
```jsx
import {Spinner} from '@inkjs/ui';;
```
### Progress bar
[Documentation](docs/progress-bar.md)
`ProgressBar` is an extended version of `Spinner`, where it's possible to calculate a progress percentage.
```jsx
import {ProgressBar} from '@inkjs/ui';// `progress` must be a number between 0 and 100
;
```
### Badge
[Documentation](docs/badge.md)
`Badge` can be used to indicate a status of a certain item, usually positioned nearby the element it's related to.
```jsx
import {Badge} from '@inkjs/ui';Pass
Fail
Warn
Todo
```
### Status message
[Documentation](docs/status-message.md)
`StatusMessage` can also be used to indicate a status, but when longer explanation of such status is required.
```jsx
import {StatusMessage} from '@inkjs/ui';New version is deployed to production
Failed to deploy a new version of this app
Health checks aren't configured
This version is already deployed
```
### Alert
[Documentation](docs/alert.md)
`Alert` is used to focus user's attention to important messages.
```jsx
import {Alert} from '@inkjs/ui';A new version of this CLI is available
Your license is expired
Current version of this CLI has been deprecated
API won't be available tomorrow night
```
### Unordered list
[Documentation](docs/unordered-list.md)
`UnorderedList` is used to show lists of items.
```jsx
import {UnorderedList} from '@inkjs/ui';
Red
Green
Light
Dark
Blue
;
```
### Ordered list
[Documentation](docs/ordered-list.md)
`OrderedList` is used to show lists of numbered items.
```jsx
import {OrderedList} from '@inkjs/ui';
Red
Green
Light
Dark
Blue
;
```
## Theming
All component have their styles defined in a theme, which is accessible to components via React context. Ink UI ships with a default theme and it can be customized or replaced with a different theme altogether.
Let's get a quick look on how to customize a `Spinner`'s component theme. Here's how it looks by default:
First, look up component's default theme, which will give an overview which parts does this component consist of. Documentation of each component includes a link to component's `theme.ts` file on top. In the case of `Spinner`, it's [source/components/spinner/theme.ts](source/components/spinner/theme.ts).
Here's the part we care about:
```tsx
const theme = {
styles: {
container: (): BoxProps => ({
gap: 1,
}),
frame: (): TextProps => ({
color: 'blue',
}),
label: (): TextProps => ({}),
},
} satisfies ComponentTheme;export default theme;
```This component theme hints that `Spinner` has 3 parts: container, frame and a label. So to customize the color of the spinner itself, we'd want to change the `color` prop returned from the `frame` function.
To customize the default theme, use `extendTheme` function and make that custom theme available to children components via `ThemeProvider`.
```tsx
import {render, type TextProps} from 'ink';
import {Spinner, ThemeProvider, extendTheme, defaultTheme} from '@inkjs/ui';const customTheme = extendTheme(defaultTheme, {
components: {
Spinner: {
styles: {
frame: (): TextProps => ({
color: 'magenta',
}),
},
},
},
});function Example() {
return (
);
}render();
```With custom theme applied, `Spinner` now renders a magenta spinner, instead of the default blue one.
There are also cases where styles change based on some condition. For example, [`StatusMessage`](docs/status-message.md) changes the color of an icon based on the `variant` prop.
Here's a sample code from its [theme](source/components/status-message/theme.ts).
```ts
const colorByVariant = {
success: 'green',
error: 'red',
warning: 'yellow',
info: 'blue',
};const theme = {
styles: {
icon: ({variant}) => ({
color: colorByVariant[variant],
}),
},
};
```Since each field in `styles` object is a function, it can return different styles based on the props that were passed in or a state of a component.
Component themes can also include configuration for rendering a component in a `config` object, that's not related to styling. For example, [`UnorderedList`](docs/unordered-list.md) specifies a `marker`, which is a character that's rendered before each list item.
Here's a sample code from its [theme](source/components/unordered-list/theme.ts).
```ts
const theme = {
config: () => ({
marker: '─',
}),
};
```
Changing `marker` to `'+'` would render this:
Components shipped in Ink UI automatically read the necessary styles and configuration from a theme. However, if you're adding a new custom component and a theme for it, use `useComponentTheme` hook to access it.
```tsx
import React, {render, Text, type TextProps} from 'ink';
import {
ThemeProvider,
defaultTheme,
extendTheme,
useComponentTheme,
type ComponentTheme,
} from '@inkjs/ui';const customLabelTheme = {
styles: {
label: (): TextProps => ({
color: 'green',
}),
},
} satisfies ComponentTheme;type CustomLabelTheme = typeof customLabelTheme;
const customTheme = extendTheme(defaultTheme, {
components: {
CustomLabel: customLabelTheme,
},
});function CustomLabel() {
const {styles} = useComponentTheme('CustomLabel');return Hello world;
}function Example() {
return (
);
}render();
```