.cursor/skills/ink-tui/references/INKJS-UI.md
Official component library for Ink. Provides themeable, production-ready UI widgets. Source: https://github.com/vadimdemedes/ink-ui
Install: npm install @inkjs/ui
All components import from @inkjs/ui. Do NOT use the older standalone packages
(ink-text-input, ink-select-input, ink-spinner) — this package supersedes them.
Single-line text input.
import { TextInput } from '@inkjs/ui';
<TextInput
placeholder="Enter your API key..."
onSubmit={(value) => { /* value is the entered string */ }}
/>
Text input validated for email format.
import { EmailInput } from '@inkjs/ui';
<EmailInput
placeholder="[email protected]"
onSubmit={(value) => { /* validated email string */ }}
/>
Masked text input for sensitive values.
import { PasswordInput } from '@inkjs/ui';
<PasswordInput
placeholder="Enter password..."
onSubmit={(value) => { /* password string */ }}
/>
Yes/No confirmation prompt.
import { ConfirmInput } from '@inkjs/ui';
<ConfirmInput
onConfirm={() => { /* user confirmed */ }}
onCancel={() => { /* user cancelled */ }}
/>
Scrollable single-select list. User picks one option.
import { Select } from '@inkjs/ui';
<Select
options={[
{ label: 'Next.js', value: 'nextjs' },
{ label: 'React (Vite)', value: 'react-vite' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte' },
]}
onChange={(newValue) => {
// newValue equals the `value` field of the selected option
// e.g. "nextjs"
}}
/>
Scrollable multi-select list. User picks one or more options.
import { MultiSelect } from '@inkjs/ui';
<MultiSelect
options={[
{ label: 'Session Recording', value: 'session-recording' },
{ label: 'Feature Flags', value: 'feature-flags' },
{ label: 'A/B Testing', value: 'ab-testing' },
{ label: 'Surveys', value: 'surveys' },
]}
onChange={(newValues) => {
// newValues is an array of selected value fields
// e.g. ["session-recording", "feature-flags"]
}}
/>
Animated loading indicator.
import { Spinner } from '@inkjs/ui';
<Spinner label="Installing dependencies..." />
Determinate progress indicator. Extended version of Spinner.
import { ProgressBar } from '@inkjs/ui';
// progress must be a number between 0 and 100
<Box width={30}>
<ProgressBar value={progress} />
</Box>
Full example with state:
const [progress, setProgress] = useState(0);
useEffect(() => {
if (progress === 100) return;
const timer = setTimeout(() => setProgress(p => p + 1), 50);
return () => clearTimeout(timer);
}, [progress]);
return (
<Box width={30}>
<ProgressBar value={progress} />
</Box>
);
Colored status indicator label.
import { Badge } from '@inkjs/ui';
<Badge color="green">Pass</Badge>
<Badge color="red">Fail</Badge>
<Badge color="yellow">Warn</Badge>
<Badge color="blue">Todo</Badge>
Status indicator with icon and longer explanation text.
import { StatusMessage } from '@inkjs/ui';
<StatusMessage variant="success">
PostHog snippet added to your app
</StatusMessage>
<StatusMessage variant="error">
Failed to install posthog-js
</StatusMessage>
<StatusMessage variant="warning">
No API key found in environment
</StatusMessage>
<StatusMessage variant="info">
Using default configuration
</StatusMessage>
Boxed alert message for important information.
import { Alert } from '@inkjs/ui';
<Alert variant="info">
Your PostHog project key was found in .env
</Alert>
Numbered list with nesting support.
import { OrderedList } from '@inkjs/ui';
<OrderedList>
<OrderedList.Item>
<Text>Install posthog-js</Text>
</OrderedList.Item>
<OrderedList.Item>
<Text>Add initialization code</Text>
<OrderedList>
<OrderedList.Item>
<Text>Import PostHog</Text>
</OrderedList.Item>
<OrderedList.Item>
<Text>Call posthog.init()</Text>
</OrderedList.Item>
</OrderedList>
</OrderedList.Item>
<OrderedList.Item>
<Text>Verify events</Text>
</OrderedList.Item>
</OrderedList>
Bulleted list with nesting support. Same API pattern as OrderedList.
All @inkjs/ui components are styled via a theme system using React context. You can customize any component's appearance.
Components work out of the box with the default theme.
import { render, type TextProps } from 'ink';
import { Spinner, ThemeProvider, extendTheme, defaultTheme } from '@inkjs/ui';
const posthogTheme = extendTheme(defaultTheme, {
components: {
Spinner: {
styles: {
frame: (): TextProps => ({
color: 'magenta',
}),
},
},
StatusMessage: {
styles: {
icon: ({ variant }): TextProps => ({
color: {
success: 'green',
error: 'red',
warning: 'yellow',
info: '#1d4aff', // PostHog blue
}[variant],
}),
},
},
},
});
function App() {
return (
<ThemeProvider theme={posthogTheme}>
<Spinner label="Loading..." />
</ThemeProvider>
);
}
render(<App />);
Each component's theme has:
styles — Functions that return TextProps or BoxProps based on component stateconfig — Non-visual configuration (like list markers, default values)Access a component's theme in custom components:
import { useComponentTheme } from '@inkjs/ui';
const theme = useComponentTheme('Spinner');
These components compose naturally with core Ink layout:
<Box flexDirection="column" gap={1}>
<Text bold>Configure PostHog features:</Text>
<MultiSelect
options={featureOptions}
onChange={setSelectedFeatures}
/>
{selectedFeatures.length > 0 && (
<StatusMessage variant="success">
{selectedFeatures.length} features selected
</StatusMessage>
)}
<Box marginTop={1}>
<Text dimColor>Press enter to continue</Text>
</Box>
</Box>