Skip to content

Ink/Chalk Compatibility

Silvery provides compatibility layers for both Ink and Chalk. This reference documents the complete API mapping.

Compatibility Summary

Test suitePass rateNotes
Ink's own test suite (via bun run compat)918/931 (~98.6%) against Ink 7.0Real Ink tests, Flexily engine
Chalk's own test suite32/32 (100%)Full Chalk API compatibility

Compatibility is tested by cloning the real Ink and Chalk repos and running their original test suites against silvery's compat layer (bun run compat). The ~13 remaining Ink test failures break down into W3C spec divergence (flex-wrap, aspect ratio — intentional: Flexily follows the spec where Yoga doesn't), build artifact expectations (silvery publishes TypeScript source + dist/), and minor rendering timing edge cases. For exact Yoga layout parity, silvery supports Yoga as a pluggable engine. See Silvery vs Ink for the full breakdown.

Ink Compatibility

Import Mapping

diff
- import { Box, Text, render, useInput, useApp } from 'ink'
+ import { Box, Text, render, useInput, useApp } from 'silvery'

- import { render } from 'ink-testing-library'
+ import { render } from '@silvery/test'

Or use the explicit compat layer:

tsx
import { Box, Text, render } from "silvery/ink"

Component Compatibility

ComponentInkSilveryNotes
<Box>SupportedSupportedSame flexbox props
<Text>SupportedSupportedAdded wrap prop
<Newline>SupportedSupportedIdentical
<Spacer>SupportedSupportedIdentical
<Static>SupportedSupportedIdentical
<Transform>SupportedSupportedIdentical

Hook Compatibility

HookInkSilveryNotes
useInput()SupportedSupportedSame callback signature
useApp()SupportedSupportedSame API
useStdout()SupportedSupportedSame API
useFocus()SupportedSupportedEnhanced with spatial navigation
useFocusManager()SupportedSupportedSame API
measureElement()SupportedSupportedWorks, but prefer useBoxRect()
useBoxMetrics()--NewPost-layout dimensions

render() Differences

tsx
// Ink
const { unmount, waitUntilExit } = render(<App />)

// Silvery -- render() is sync, returns RenderHandle; .run() is async
const app = render(<App />)
await app.run()

// Silvery -- with explicit terminal
using term = createTerm()
const app = render(<App />, term)
await app.run()

Behavior Differences

BehaviorInkSilveryReason
Default flexDirectioncolumnrowW3C CSS spec compliance
Text overflowOverflows containerWraps by defaultBetter default
First render dimensionsN/A{ width: 0, height: 0 }Required for responsive layout
overflow valuesvisible, hiddenvisible, hidden, scrollScrolling support
Internal APIsExposedHiddenNot public API

Layout engine note: Silvery defaults to Flexily, which follows the W3C CSS spec where Yoga diverges. For exact Ink layout parity (e.g., flexWrap, alignContent, percentage flexBasis), use Yoga as the layout engine. See Flexily vs Yoga Philosophy.

Flexbox Props

All flexbox props work identically:

PropInkSilvery
flexDirectionSupportedSupported
flexGrowSupportedSupported
flexShrinkSupportedSupported
flexBasisSupportedSupported
justifyContentSupportedSupported
alignItemsSupportedSupported
alignSelfSupportedSupported
flexWrapSupportedSupported
width / heightSupportedSupported
minWidth / minHeightSupportedSupported
maxWidth / maxHeightSupportedSupported
padding / paddingX / paddingYSupportedSupported
margin / marginX / marginYSupportedSupported
gapNot supportedSupported

Border Styles

All border styles work identically: single, double, round, bold, classic, arrow, heavy, doubleSingle, singleDouble.

Chalk Compatibility

Import Mapping

diff
- import chalk from 'chalk'
+ import chalk from 'silvery/chalk'

Feature Support

FeatureChalksilvery/chalk
Standard colorschalk.red()Supported
Bright colorschalk.redBright()Supported
Background colorschalk.bgRed()Supported
Modifierschalk.bold(), chalk.dim(), etc.Supported
RGB colorschalk.rgb(255, 0, 0)Supported
Hex colorschalk.hex('#ff0000')Supported
256 colorschalk.ansi256(196)Supported
Chainingchalk.red.bold.underline()Supported
Template literalschalk`{red text}`Supported
chalk.levelColor level detectionSupported

Chalk Strings in Components

Chalk-styled strings work inside Silvery's <Text> component:

tsx
import chalk from "silvery/chalk"
import { Text } from "silvery"

<Text>{chalk.red.bold("Error!")}</Text>
<Text>{chalk.green("Success")} and {chalk.yellow("warning")}</Text>

Compat Layer Architecture

The Ink compatibility layer (@silvery/ink) is built as thin adapters that bridge Ink's APIs to silvery-native systems. Understanding the architecture helps you decide when to use Ink-compat hooks vs silvery-native ones.

How It Works

withInk(), pipe(), and createApp() are available from @silvery/create. For straightforward use, render() is sufficient. The composition APIs are for apps that need fine-grained control over which Ink adapters to load.

withInk() composes two independent plugins:

typescript
// withInk() = withInkCursor() + withInkFocus()
const app = pipe(
  createApp(store),
  withReact(<App />),
  withTerminal(process),
  withInk(), // applies both adapters
)
PluginInk APIBridges toSize
withInkCursor()useCursor()silvery CursorStore~50 lines
withInkFocus()useFocus(), useFocusManager()InkFocusProvider (flat list)~45 lines

Error handling is not part of the compat layer — silvery's built-in SilveryErrorBoundary wraps all apps automatically in createApp().

Ink Focus vs Silvery Focus

The two focus systems have fundamentally different designs:

Ink Focus (useFocus)Silvery Focus (useFocusable)
ModelFlat list of component-registered IDsTree of layout nodes with spatial awareness
NavigationTab/Shift+Tab onlyTab, arrow keys (spatial), click-to-focus
ScopingNone — all focusables in one global listFocus scopes isolate regions (e.g., modal dialogs)
RegistrationComponents call add(id) / remove(id)Automatic from layout tree
EventsNoneDOM-style focus/blur with capture/target/bubble

For new code, use silvery's focus system. The Ink compat focus exists for apps that already use Ink's useFocus() / useFocusManager().

Ink Cursor vs Silvery Cursor

Both systems write to the same CursorStorewithInkCursor() just provides the InkCursorStoreCtx context that Ink's useCursor() hook reads from. The underlying cursor mechanism is identical.

Silvery-Only Features

These features have no Ink/Chalk equivalent:

FeatureAPI
Layout feedbackuseBoxRect()
Scrollable containersoverflow="scroll" + scrollTo
Input layer isolation<InputLayerProvider>
Spatial focus<FocusScope> with arrow keys
Mouse eventsonClick, onMouseDown, onWheel
Command systemwithCommands()
Theme tokenscolor="$fg-accent" (Sterling)
TextAreaBuilt-in multi-line editing
45+ componentsVirtualList, Table, ModalDialog, etc.

See Also