Ink Web

Next.js Integration

Using ink-web with Next.js

Next.js Integration

This guide shows you how to use ink-web with Next.js, including how to handle client-side only rendering and edge runtime.

Installation

First, install the required dependencies:

npm install ink-web react xterm
# or
bun add ink-web react xterm

Using the Bundled Version

For Next.js, we recommend using the bundled version of ink-web as it's easier to configure:

'use client';

import { InkTerminalBox, Box, Text, useInput } from 'ink-web/bundled';
import 'ink-web/bundled/css';
import 'xterm/css/xterm.css';
import { useState } from 'react';

export function MyTerminal() {
  const [input, setInput] = useState('');

  useInput((inputChar, key) => {
    if (key.return) {
      console.log('User entered:', input);
      setInput('');
    } else if (key.backspace || key.delete) {
      setInput((prev) => prev.slice(0, -1));
    } else if (!key.ctrl && !key.meta && inputChar) {
      setInput((prev) => prev + inputChar);
    }
  });

  return (
    <InkTerminalBox focus>
      <Box flexDirection="column">
        <Text color="green">Hello from Next.js!</Text>
        <Text>
          <Text color="cyan">&gt; </Text>
          <Text>{input}</Text>
          <Text inverse> </Text>
        </Text>
      </Box>
    </InkTerminalBox>
  );
}

Client-Side Only Rendering

Since ink-web relies on browser APIs (like document), you need to mark components using it with 'use client' directive at the top of the file.

Alternatively, you can use Next.js dynamic imports with SSR disabled:

import dynamic from 'next/dynamic';

const MyTerminal = dynamic(() => import('./components/MyTerminal'), {
  ssr: false,
});

export default function Page() {
  return (
    <div>
      <h1>My Terminal App</h1>
      <MyTerminal />
    </div>
  );
}

Edge Runtime

If you want to use Next.js Edge Runtime, you can configure it in your next.config.js:

/** @type {import('next').NextConfig} */
const config = {
  reactStrictMode: true,
  experimental: {
    runtime: 'edge',
  },
};

export default config;

Or for specific pages/routes:

export const runtime = 'edge';

export default function Page() {
  return <MyTerminal />;
}

Common Issues

Module Not Found Errors

If you encounter module resolution errors during build, you may need to add some polyfills to your next.config.js:

/** @type {import('next').NextConfig} */
const config = {
  webpack: (config) => {
    config.resolve.fallback = {
      ...config.resolve.fallback,
      fs: false,
      net: false,
      tls: false,
    };
    return config;
  },
};

export default config;

Hydration Errors

If you see hydration errors, make sure you're using the 'use client' directive or dynamic imports with ssr: false.