# Bullet List

Nested structured content with ●/└/□ bullet prefixes

## Installation

  <TabsTrigger value="cli">Command</TabsTrigger>
  <TabsTrigger value="manual">Manual</TabsTrigger>

```bash
npx shadcn@latest add @termcn/bullet-list
```

<Step>Copy and paste the following code into your project.</Step>

```tsx
/* @jsxImportSource @opentui/react */
import type { ReactNode } from "react";

import { useTheme } from "@/components/ui/theme-provider";

export interface BulletListItemProps {
  label: string;
  bold?: boolean;
  color?: string;
  children?: ReactNode;
}

export interface BulletListTreeItemProps {
  label: string;
  color?: string;
}

export interface BulletListCheckItemProps {
  label: string;
  done?: boolean;
  color?: string;
}

const BulletListRoot = ({ children }: { children: ReactNode }) => (
  <box flexDirection="column">{children}</box>
);

const BulletListItem = ({
  label,
  bold: boldText = false,
  color,
  children,
}: BulletListItemProps) => {
  const theme = useTheme();
  return (
    <box flexDirection="column">
      <box flexDirection="row">
        <text fg={color ?? theme.colors.primary}>{"● "}</text>
        {boldText ? (
          <text fg={color}>
            <b>{label}</b>
          </text>
        ) : (
          <text fg={color}>{label}</text>
        )}
      </box>
      {children}
    </box>
  );
};

const BulletListSub = ({ children }: { children: ReactNode }) => (
  <box flexDirection="column" paddingLeft={2}>
    {children}
  </box>
);

const BulletListTreeItem = ({ label, color }: BulletListTreeItemProps) => {
  const theme = useTheme();
  return (
    <box flexDirection="row">
      <text fg={theme.colors.mutedForeground}>{"└ "}</text>
      <text fg={color}>{label}</text>
    </box>
  );
};

const BulletListCheckItem = ({
  label,
  done = false,
  color,
}: BulletListCheckItemProps) => {
  const theme = useTheme();
  const icon = done ? "■" : "□";
  const resolvedColor =
    color ?? (done ? theme.colors.success : theme.colors.mutedForeground);
  return (
    <box flexDirection="row">
      <text fg={resolvedColor}>{`${icon} `}</text>
      <text fg={done ? undefined : color}>{label}</text>
    </box>
  );
};

export const BulletList = Object.assign(BulletListRoot, {
  CheckItem: BulletListCheckItem,
  Item: BulletListItem,
  Sub: BulletListSub,
  TreeItem: BulletListTreeItem,
});
```

<Step>Update the import paths to match your project setup.</Step>

## Usage

```tsx
import { BulletList } from "@/components/ui/bullet-list";
```

```tsx
<BulletList>
  <BulletList.Item label="Install dependencies" bold>
    <BulletList.Sub>
      <BulletList.TreeItem label="opentui@5.1.0" />
      <BulletList.TreeItem label="react@18.3.0" />
    </BulletList.Sub>
  </BulletList.Item>
  <BulletList.Item label="Configure project" />
  <BulletList.CheckItem label="Write tests" done />
  <BulletList.CheckItem label="Deploy to production" />
</BulletList>
```

## API Reference

### BulletList

| Prop       | Type        | Default    |
| ---------- | ----------- | ---------- |
| `children` | `ReactNode` | `required` |

### BulletList.Item

| Prop       | Type        | Default    |
| ---------- | ----------- | ---------- |
| `label`    | `string`    | `required` |
| `bold`     | `boolean`   | `false`    |
| `color`    | `string`    | -          |
| `children` | `ReactNode` | -          |

### BulletList.Sub

| Prop       | Type        | Default    |
| ---------- | ----------- | ---------- |
| `children` | `ReactNode` | `required` |

### BulletList.TreeItem

| Prop    | Type     | Default    |
| ------- | -------- | ---------- |
| `label` | `string` | `required` |
| `color` | `string` | -          |

### BulletList.CheckItem

| Prop    | Type      | Default    |
| ------- | --------- | ---------- |
| `label` | `string`  | `required` |
| `done`  | `boolean` | `false`    |
| `color` | `string`  | -          |