Box

Box lays out child renderables and can draw a background, border, and title. Use ScrollBox when the children must scroll.

Availability

FieldAvailability
Package@opentui/core
Core renderableBoxRenderable
React<box> (automatic)
Solid<box> (automatic)
StatusBuilt in

Basic usage

Renderable API

OpenTUI preview

Run this example to open an interactive terminal.

Source code · typescript
import { BoxRenderable, TextRenderable, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const panel = new BoxRenderable(renderer, {
  id: "panel",
  width: 30,
  height: 10,
  backgroundColor: "#333366",
  borderStyle: "double",
  borderColor: "#FFFFFF",
})

renderer.root.add(panel)

Border styles

// No border
{
  border: false
}

// Simple border (default style)
{
  border: true
}

// Specific border styles
{
  borderStyle: "single"
} // Single line: ┌─┐│└─┘
{
  borderStyle: "double"
} // Double line: ╔═╗║╚═╝
{
  borderStyle: "rounded"
} // Rounded corners: ╭─╮│╰─╯
{
  borderStyle: "heavy"
} // Heavy lines: ┏━┓┃┗━┛
┌─────single─────┐  ╔═════double═════╗
│ single line    │  ║ double lines   ║
└────────────────┘  ╚════════════════╝

╭────rounded─────╮  ┏━━━━━heavy━━━━━━┓
│ round corners  │  ┃ heavy strokes  ┃
╰────────────────╯  ┗━━━━━━━━━━━━━━━━┛

Titles

Add a title and bottom title to the box border:

const panel = new BoxRenderable(renderer, {
  id: "settings",
  width: 40,
  height: 15,
  borderStyle: "rounded",
  title: "Settings",
  titleColor: "yellow",
  titleAlignment: "center",
  bottomTitle: "Footer",
  bottomTitleAlignment: "center",
})

Title alignment (both top and bottom titles)

{
  titleAlignment: "left"
} // ┌─ Title ────────┐
{
  titleAlignment: "center"
} // ┌──── Title ─────┐
{
  titleAlignment: "right"
} // ┌────────── Title ┐

{
  bottomTitleAlignment: "left"
} // └─ Title ────────┘
{
  bottomTitleAlignment: "center"
} // └──── Title ─────┘
{
  bottomTitleAlignment: "right"
} // └────────── Title ┘
┌───────────settings───────────┐
│ Top and bottom titles        │
└────────────────────────close─┘

Layout container

Box works as a flex container for child elements:

const container = new BoxRenderable(renderer, {
  flexDirection: "column",
  justifyContent: "space-between",
  alignItems: "stretch",
  width: 50,
  height: 20,
  padding: 1,
  gap: 1,
})
const content = new BoxRenderable(renderer, { flexGrow: 1, backgroundColor: "#222" })

content.add(new TextRenderable(renderer, { content: "Content area" }))
container.add(new TextRenderable(renderer, { content: "Header" }))
container.add(content)
container.add(new TextRenderable(renderer, { content: "Footer" }))

Mouse events

Handle mouse interactions on the box:

const button = new BoxRenderable(renderer, {
  id: "button",
  width: 12,
  height: 3,
  border: true,
  backgroundColor: "#444",
  onMouseDown: () => {
    console.log("Button clicked!")
  },
  onMouseOver: () => {
    button.backgroundColor = "#666"
  },
  onMouseOut: () => {
    button.backgroundColor = "#444"
  },
})

Properties

PropertyTypeDefaultDescription
widthnumber | string-Width in terminal columns or percentage
heightnumber | string-Height in rows or percentage
backgroundColorstring | RGBAtransparentBackground fill color
borderbooleanfalseShow border
borderStylestring"single"Border style
borderColorstring | RGBA#FFFFFFBorder color
titlestring-Title text in border
titleColorstring | RGBAborderColorColor of the title text
titleAlignmentstring"left"Title position
bottomTitlestring-Bottom title text in border
bottomTitleAlignmentstring"left"Bottom title position
paddingnumber0Internal padding
gapnumber | string-Gap between children
flexDirectionstring"column"Child layout direction
justifyContentstring"flex-start"Main axis alignment
alignItemsstring"stretch"Cross axis alignment

Example: card component

import { BoxRenderable, TextRenderable, t, bold, fg } from "@opentui/core"

function Card(props: { title: string; description: string }) {
  const card = new BoxRenderable(renderer, {
    width: 40,
    borderStyle: "rounded",
    borderColor: "#666",
    padding: 1,
    margin: 1,
  })
  card.add(
    new TextRenderable(renderer, {
      content: t`${bold(fg("#00FFFF")(props.title))}`,
    }),
  )
  card.add(
    new TextRenderable(renderer, {
      content: props.description,
      fg: "#AAAAAA",
    }),
  )
  return card
}

const cards = new BoxRenderable(renderer, { flexDirection: "row", flexWrap: "wrap" })
cards.add(Card({ title: "Feature 1", description: "Description of feature 1" }))
cards.add(Card({ title: "Feature 2", description: "Description of feature 2" }))
cards.add(Card({ title: "Feature 3", description: "Description of feature 3" }))
renderer.root.add(cards)

Read Layout for sizing and flex behavior. See Colors for color formats and Interaction, focus, and selection for mouse event propagation. Use Text for labels and other text content.

Changes0.8.0
0.8.0
core: A box title is placed against the box’s own edges, so a box at a negative x or past the right edge of the screen shows its title in the correct place. (#1797)