Use when managing state and side effects in Ink applications using React hooks for terminal UIs.
View on GitHubTheBushidoCollective/han
jutsu-ink
January 24, 2026
Select agents to install to:
npx add-skill https://github.com/TheBushidoCollective/han/blob/main/jutsu/jutsu-ink/skills/ink-hooks-state/SKILL.md -a claude-code --skill ink-hooks-stateInstallation paths:
.claude/skills/ink-hooks-state/# Ink Hooks and State Management
You are an expert in managing state and side effects in Ink applications using React hooks.
## Core Hooks
### useState - Local State
```tsx
import { Box, Text } from 'ink';
import React, { useState } from 'react';
const Counter: React.FC = () => {
const [count, setCount] = useState(0);
return (
<Box>
<Text>Count: {count}</Text>
</Box>
);
};
```
### useEffect - Side Effects
```tsx
import { useEffect, useState } from 'react';
const DataLoader: React.FC<{ fetchData: () => Promise<string[]> }> = ({ fetchData }) => {
const [data, setData] = useState<string[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
fetchData()
.then((result) => {
setData(result);
setLoading(false);
})
.catch((err: Error) => {
setError(err);
setLoading(false);
});
}, [fetchData]);
if (loading) return <Text>Loading...</Text>;
if (error) return <Text color="red">Error: {error.message}</Text>;
return (
<Box flexDirection="column">
{data.map((item, i) => (
<Text key={i}>{item}</Text>
))}
</Box>
);
};
```
### useInput - Keyboard Input
```tsx
import { useInput } from 'ink';
import { useState } from 'react';
const InteractiveMenu: React.FC<{ onExit: () => void }> = ({ onExit }) => {
const [selectedIndex, setSelectedIndex] = useState(0);
const items = ['Option 1', 'Option 2', 'Option 3'];
useInput((input, key) => {
if (key.upArrow) {
setSelectedIndex((prev) => Math.max(0, prev - 1));
}
if (key.downArrow) {
setSelectedIndex((prev) => Math.min(items.length - 1, prev + 1));
}
if (key.return) {
// Handle selection
}
if (input === 'q' || key.escape) {
onExit();
}
});
return (
<Box flexDirection="column">
{items.map((item, i) => (
<Text key={i} color={i === selectedIndex ? 'cya