[//]: # (This file is auto-generated by the docs:generate-skills script, do not edit it manually)

# Preview

Import: `import { Preview } from '@neo4j-ndl/react/ai'`

## Props

### Preview

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` | ✅ |  |  |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |

### Preview.Code

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `code` | `string` | ✅ |  | The code content to display |
| `headerActions` | `ReactNode` |  |  | The actions to display in the header. Should be small buttons or icon buttons only. |
| `heading` | `string` |  |  | The heading to display in the header. If not provided, the language will be displayed. Truncates with an ellipsis and shows a tooltip with the full text when space is limited. |
| `isLoading` | `boolean` |  | `false` | Whether the code block is loading |
| `label` | `'read' \| 'write'` |  |  | The current state of the code block @deprecated - The query should be described in the heading property instead. |
| `language` | `any` | ✅ |  | The language of the code (e.g., 'cypher', 'python', 'javascript') |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |
| `theme` | `'ndl-code-dark' \| 'ndl-code-light'` |  |  | The theme of the code block |

### Preview.Confirmation

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `actions` | `ReactNode` | ✅ |  | The actions to display in the confirmation, usually two buttons; one for confirming and one for rejecting. |
| `children` | `ReactNode` |  |  | The content to display in the confirmation |
| `confirmedActionText` | `string` |  | `Action confirmed` | The text to display for the confirmed status |
| `isFooter` | `boolean` |  | `false` | Whether the confirmation is used as a footer |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |
| `rejectedActionText` | `string` |  | `Action rejected` | The text to display for the rejected status |
| `status` | `'confirmed' \| 'pending' \| 'rejected'` |  | `pending` | The status of the confirmation |

### Preview.Content

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `ReactNode` |  |  |  |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |

### Preview.Header

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `actions` | `ReactNode` |  |  | The actions to display in the header. Should be small buttons or icon buttons only. |
| `children` | `ReactNode` |  |  | The content to display in the header. When a plain string is passed, it truncates with an ellipsis and shows a tooltip with the full text when space is limited. |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |

## Accessibility

## Keyboard interactions

| Key      | Description                                                                            |
| -------- | -------------------------------------------------------------------------------------- |
| `Tab`    | Moves focus to the header heading when it is truncated, then to the header actions     |
| `Escape` | Closes the tooltip showing the full heading text                                       |

## Truncated header heading

When the header heading (the `heading` of `Preview.Code`, or a plain string passed to `Preview.Header`) does not fit the available space, it truncates with an ellipsis and a tooltip with the full text becomes available.

- The heading receives `tabIndex="0"` only while the text is actually clipped, so keyboard users can reveal the full text on focus without a dead tab stop when nothing is hidden
- The tooltip opens on hover and on keyboard focus, and is dismissible with `Escape` while remaining hoverable and persistent per [WCAG 1.4.13 Content on Hover or Focus](https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html)
- The heading is intentionally not a button: it performs no action, so button semantics would announce an interaction that does not exist
- Screen readers always receive the full heading text from the element's own content — CSS truncation is visual-only and does not remove text from the accessibility tree. The tooltip primarily serves sighted mouse and keyboard users
- The focused heading shows a visible focus outline

### Related WCAG criteria

- [1.4.13 Content on Hover or Focus](https://www.w3.org/WAI/WCAG22/Understanding/content-on-hover-or-focus.html) (AA): The tooltip is dismissible (`Escape`), hoverable, and persistent
- [2.1.1 Keyboard](https://www.w3.org/WAI/WCAG22/Understanding/keyboard.html) (A): The full heading text is reachable via keyboard focus when truncated
- [2.4.7 Focus Visible](https://www.w3.org/WAI/WCAG22/Understanding/focus-visible.html) (AA): The truncated heading shows a focus outline when focused via keyboard

## Examples

### Code Confirmation

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, OutlinedButton } from '@neo4j-ndl/react';
import { Preview } from '@neo4j-ndl/react/ai';
import { useState } from 'react';

const cypherCode = `SHOW [ALL|BUILT IN|USER DEFINED] FUNCTION[S] EXECUTABLE BY
username
[YIELD { * | field[, ...] } [ORDER BY field ...`;

const Component = () => {
  const [status, setStatus] =
    useState<React.ComponentProps<typeof Preview.Confirmation>['status']>(
      'pending',
    );

  return (
    <Preview>
      <Preview.Code
        code={cypherCode}
        language="cypher"
        heading="Show functions executable by user"
        isLoading={false}
        headerActions={null}
      />
      <Preview.Confirmation
        status={status}
        isFooter={true}
        confirmedActionText="Action confirmed"
        rejectedActionText="Action rejected"
        actions={
          <>
            <OutlinedButton
              variant="neutral"
              size="small"
              onClick={() => setStatus('rejected')}
            >
              Skip
            </OutlinedButton>
            <FilledButton
              variant="primary"
              size="small"
              onClick={() => setStatus('confirmed')}
            >
              Run query
            </FilledButton>
          </>
        }
      >
        Assistant wants to run this query
      </Preview.Confirmation>
    </Preview>
  );
};

export default Component;
```

### Code Cypher

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { OutlinedButton } from '@neo4j-ndl/react';
import { Preview } from '@neo4j-ndl/react/ai';
import { PencilSquareIconOutline } from '@neo4j-ndl/react/icons';

const cypherCode = `SHOW [ALL|BUILT IN|USER DEFINED] FUNCTION[S] EXECUTABLE BY
username
[YIELD { * | field[, ...] } [ORDER BY field ...`;

const Component = () => {
  return (
    <Preview>
      <Preview.Code
        code={cypherCode}
        language="cypher"
        heading="Show functions executable by user"
        headerActions={
          <OutlinedButton
            leadingVisual={<PencilSquareIconOutline />}
            variant="neutral"
            size="small"
          >
            Send to Query
          </OutlinedButton>
        }
      />
    </Preview>
  );
};

export default Component;
```

### Code Languages

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Preview } from '@neo4j-ndl/react/ai';

const pythonCode = `def show_functions(username, function_type='ALL'):
    """
    Show functions executable by user
    """
    query = f"SHOW {function_type} FUNCTIONS EXECUTABLE BY {username}"
    return query`;

const Component = () => {
  return (
    <Preview>
      <Preview.Code
        code={pythonCode}
        language="python"
        heading="Show functions executable by user"
      />
    </Preview>
  );
};

export default Component;
```

### Code Loading

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { Preview } from '@neo4j-ndl/react/ai';

const Component = () => {
  return (
    <Preview>
      <Preview.Code code="" language="cypher" isLoading={true} />
    </Preview>
  );
};

export default Component;
```

### Code Truncation

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { OutlinedButton } from '@neo4j-ndl/react';
import { Preview } from '@neo4j-ndl/react/ai';
import { PencilSquareIconOutline } from '@neo4j-ndl/react/icons';

const cypherCode = `MATCH (person:Person)-[:ACTED_IN]->(movie:Movie)
WHERE movie.released > 2000
RETURN person.name, movie.title`;

const Component = () => {
  return (
    <div style={{ maxWidth: 400 }}>
      <Preview>
        <Preview.Code
          code={cypherCode}
          language="cypher"
          heading="Find all people who acted in movies released after the year 2000"
          headerActions={
            <OutlinedButton
              leadingVisual={<PencilSquareIconOutline />}
              variant="neutral"
              size="small"
            >
              Send to Query
            </OutlinedButton>
          }
        />
      </Preview>
    </div>
  );
};

export default Component;
```

### Confirmation Standalone

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, OutlinedButton } from '@neo4j-ndl/react';
import { Preview } from '@neo4j-ndl/react/ai';
import { useState } from 'react';

const Component = () => {
  const [status, setStatus] =
    useState<React.ComponentProps<typeof Preview.Confirmation>['status']>(
      'pending',
    );

  return (
    <Preview>
      <Preview.Confirmation
        status={status}
        isFooter={false}
        confirmedActionText="Action confirmed"
        rejectedActionText="Action rejected"
        actions={
          <>
            <OutlinedButton
              variant="neutral"
              size="small"
              onClick={() => setStatus('rejected')}
            >
              Reject
            </OutlinedButton>
            <FilledButton
              variant="primary"
              size="small"
              onClick={() => setStatus('confirmed')}
            >
              Confirm
            </FilledButton>
          </>
        }
      >
        This confirmation is used when the assistant does not have a preview,
        but asks about doing something in plain text on top of the canvas in the
        chat. Do you approve this action?
      </Preview.Confirmation>
    </Preview>
  );
};

export default Component;
```

### Data Grid

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { DataGrid, FilledButton, OutlinedButton } from '@neo4j-ndl/react';
import { Preview } from '@neo4j-ndl/react/ai';
import {
  getCoreRowModel,
  getSortedRowModel,
  useReactTable,
} from '@tanstack/react-table';
import { useState } from 'react';

const DATA = [
  {
    project_role: 'Viewer',
    user: 'John Doe',
  },
  {
    project_role: 'Viewer',
    user: 'Alice Appleton',
  },
  {
    project_role: 'Editor',
    user: 'Bob Blueburr',
  },
];

const Component = () => {
  const [status, setStatus] =
    useState<React.ComponentProps<typeof Preview.Confirmation>['status']>(
      'pending',
    );

  const table = useReactTable({
    columns: [
      {
        accessorKey: 'user',
        header: 'User',
      },
      {
        accessorKey: 'project_role',
        header: 'Project Role',
      },
    ],
    data: DATA,
    defaultColumn: {
      minSize: 100,
    },
    enableSorting: true,
    getCoreRowModel: getCoreRowModel(),
    getSortedRowModel: getSortedRowModel(),
  });

  return (
    <Preview>
      <DataGrid
        isResizable={false}
        tableInstance={table}
        isKeyboardNavigable={false}
        styling={{
          borderStyle: 'all-sides',
        }}
        components={{
          Navigation: null,
        }}
      />
      <Preview.Confirmation
        isFooter={true}
        status={status}
        actions={
          <>
            <OutlinedButton
              variant="neutral"
              size="small"
              onClick={() => setStatus('rejected')}
            >
              Skip
            </OutlinedButton>
            <FilledButton
              variant="primary"
              size="small"
              onClick={() => setStatus('confirmed')}
            >
              Invite users
            </FilledButton>
          </>
        }
      >
        Assistant wants to perform an action
      </Preview.Confirmation>
    </Preview>
  );
};

export default Component;
```

### Simple

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, OutlinedButton } from '@neo4j-ndl/react';
import { Preview } from '@neo4j-ndl/react/ai';
import { useState } from 'react';

const Component = () => {
  const [status, setStatus] =
    useState<React.ComponentProps<typeof Preview.Confirmation>['status']>(
      'pending',
    );

  return (
    <Preview>
      <Preview.Header>CONNECT TO INSTANCE</Preview.Header>
      <Preview.Confirmation
        status={status}
        isFooter={true}
        confirmedActionText="Instance selected"
        rejectedActionText="Skipped"
        actions={
          <>
            <OutlinedButton
              variant="neutral"
              size="small"
              onClick={() => setStatus('rejected')}
            >
              Skip
            </OutlinedButton>
            <FilledButton
              variant="primary"
              size="small"
              onClick={() => setStatus('confirmed')}
            >
              Select instance
            </FilledButton>
          </>
        }
      ></Preview.Confirmation>
    </Preview>
  );
};

export default Component;
```

### Simple With Content

```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';

import { FilledButton, OutlinedButton, ReadOnlyTag } from '@neo4j-ndl/react';
import { Preview } from '@neo4j-ndl/react/ai';
import { DeploymentsIcon } from '@neo4j-ndl/react/icons';
import { useState } from 'react';

const Component = () => {
  const [status, setStatus] =
    useState<React.ComponentProps<typeof Preview.Confirmation>['status']>(
      'pending',
    );

  return (
    <Preview>
      <Preview.Header>CONNECT TO INSTANCE</Preview.Header>
      <Preview.Content>
        <ReadOnlyTag size="small" leadingVisual={<DeploymentsIcon />}>
          Instance 1
        </ReadOnlyTag>
      </Preview.Content>
      <Preview.Confirmation
        status={status}
        isFooter={true}
        confirmedActionText="Allowed action"
        rejectedActionText="Skipped action"
        actions={
          <>
            <OutlinedButton
              variant="neutral"
              size="small"
              onClick={() => setStatus('rejected')}
            >
              Skip
            </OutlinedButton>
            <FilledButton
              variant="primary"
              size="small"
              onClick={() => setStatus('confirmed')}
            >
              Allow
            </FilledButton>
          </>
        }
      ></Preview.Confirmation>
    </Preview>
  );
};

export default Component;
```
