Галерея элементов интерфейса для модов
Посмотрите, какие элементы интерфейса может отрисовывать мод Claude Code: текст, кнопки, поля, Markdown, код и diff, — с примерами кода и снимками экрана терминала.
Мод строит свой интерфейс из элементов: текста, блоков, кнопок, полей и нескольких элементов, которые форматируют содержимое за вас. Примеры на этой странице показывают код, отрисовывающий элемент, и к большинству из них приложен снимок экрана с результатом на панели терминала, поэтому элемент можно выбрать по его внешнему виду.
Чтобы разобраться, как работает отрисовка, начните с раздела Отрисовка в интерфейсе. Основные свойства элементов и приложения, которые отрисовывают каждый из них, описаны в справочнике по элементам. В объявлениях типов перечислены все свойства.
Попробуйте пример
Примеры на этой странице — это фрагменты, а не готовые моды. Каждый из них — код одного элемента и всего, что в него вложено.
Чтобы посмотреть пример в своём терминале, создайте небольшой мод, следуя этим шагам, и вставьте в него пример. Мод добавляет команду /gallery, которая открывает панель и отрисовывает в ней пример. Панель — это боковая область рядом с транскриптом в широком полноэкранном терминале, а в остальных случаях — область в рамке над промптом.
1. Создайте мод
Создайте каталог gallery, а внутри него — каталоги .claude-plugin и hooks. Назначение файлов объясняется в разделе Создание мода.
Сохраните манифест как gallery/.claude-plugin/plugin.json:
{
"name": "gallery",
"version": "0.1.0",
"description": "Opens a pane that draws one sample",
"author": { "name": "Your Name" }
}
Укажите точку входа в gallery/hooks/hooks.json:
{
"modules": ["./register.js"]
}
Сохраните код как gallery/hooks/register.js. Он добавляет команду /gallery, которая открывает панель, и отрисовывает в ней Plain text:
// Stands in for your own callback in the samples that take one
const noop = () => {}
// The Select sample keeps its choice here
let picked = 'md'
// The Raster sample packs its cells with this function
const DEFAULT_COLOR = 0x01000000
function cellsOf(rows) {
const numbers = rows.flat().flatMap(([char, color]) => [char.codePointAt(0), color, DEFAULT_COLOR])
return new Uint8Array(Uint32Array.from(numbers).buffer).toBase64()
}
export function register(on) {
on('session.start', async ($, e, next) => {
await $.command.register({ name: 'gallery', description: 'Open the sample pane' })
return next(e)
})
on('command.run', { command: 'gallery' }, async ($) => {
await $.ui.open({ id: 'gallery', focus: true, closeOnEscape: true })
return {}
})
on('ui.render', { component: 'Pane' }, async ($, e, next) => {
if (e.requestId !== 'gallery') return next(e)
const { Box, Text, Button, Input, Select, Link, Markdown, Code, Raster, Svg } = $.ui.resolve(e)
// Replace the element after return with a sample
return Text({ children: ['Plain text'] })
})
}
2. Запустите мод
В оболочке запустите Claude Code из каталога, содержащего gallery:
claude --plugin-dir ./gallery
В промпте Claude Code выполните /gallery. Откроется панель с текстом Plain text.
3. Подставьте пример
Скопируйте пример с этой страницы. В register.js вставьте его вместо Text({ children: ['Plain text'] }), чтобы он шёл после return, и сохраните файл. Claude Code перезагружает модуль при каждом сохранении, поэтому снова выполните /gallery, чтобы увидеть новый пример.
Выберите элемент
Примеры сгруппированы по тому, что вы хотите вывести на экран:
- Вывод текста:
Text,MarkdownиLink - Вывод кода и изменений:
Code - Компоновка элементов:
Box - Ввод данных:
Button,InputиSelect - Рисование изображений:
Raster,Svg,ImageиClient
Вывод текста
Текст на экран выводят три элемента: Text — с вашим собственным оформлением, Markdown — для уже отформатированного содержимого и Link — для URL.
Text
Text отрисовывает строку с заданными вами стилями. В этом примере показаны обычный текст и восемь стилей, каждый на отдельной строке:
Box({
flexDirection: 'column',
children: [
Text({ children: ['Plain text'] }),
Text({ bold: true, children: ['bold'] }),
Text({ italic: true, children: ['italic'] }),
Text({ underline: true, children: ['underline'] }),
Text({ strikethrough: true, children: ['strikethrough'] }),
Text({ dimColor: true, children: ['dimColor'] }),
Text({ inverse: true, children: ['inverse'] }),
Text({ color: 'red', children: ["color: 'red'"] }),
Text({ backgroundColor: 'blue', children: ["backgroundColor: 'blue'"] }),
],
})

dimColor отрисовывает текст серым цветом. backgroundColor заливает фон только по ширине текста.
Markdown
Markdown форматирует текст так же, как форматируются ответы Claude. Передавайте содержимое в text, а не в children:
Markdown({
text: '## Release notes\n\nThis build has **two** fixes and one `flag`:\n\n- Faster start\n- Fewer prompts\n\n> Quoted text',
})

Заголовок отрисовывается жирным шрифтом без знаков #. Встроенный код отрисовывается цветом без обратных кавычек. Цитата отрисовывается курсивом с чертой слева.
Link
Link отрисовывает подпись, а за ней — её URL:
Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })

Терминал отрисовывает URL как текст после подписи. Откроется ли он по щелчку, зависит от терминала пользователя.
Вывод кода и изменений
Code отрисовывает исходный текст с подсветкой синтаксиса в цветах самого Claude Code или diff. В расширении VS Code Code показывает свой source как обычный текст, без цветов, номеров строк и подсветки diff, которые видны на этих снимках экрана.
Code
Укажите язык в language или передайте path, чтобы Claude Code определил язык по нему. С startLine строки нумеруются начиная с этого числа:
Code({
language: 'javascript',
startLine: 1,
source: "const name = 'mods'\nconsole.log('hello ' + name)",
})

Цвета берутся из темы пользователя.
Code в виде diff
С format: 'diff' в source передаются один или несколько фрагментов (hunks) в формате unified diff:
Code({
format: 'diff',
source: '@@ -1,3 +1,3 @@\n # Mods\n-A mod is a plugin.\n+A mod is a plugin that runs code.\n Read on.',
})

Вместо строки @@ Claude Code отрисовывает номера строк. Если удалённая и добавленная строки похожи, изменившиеся слова подсвечиваются ярче.
Компоновка элементов
Box
Box располагает своё содержимое в строку или в столбец и может отрисовывать рамку. В этом примере над блоком в рамке размещается строка слов:
Box({
flexDirection: 'column',
gap: 1,
children: [
Box({
flexDirection: 'row',
columnGap: 4,
children: [Text({ children: ['a row'] }), Text({ children: ['of three'] }), Text({ children: ['items'] })],
}),
Box({
borderStyle: 'round',
paddingX: 1,
children: [Text({ children: ["borderStyle: 'round'"] })],
}),
],
})

Рамка растягивается на всю ширину панели.
Ввод данных
Button, Input и Select — это элементы управления: пользователь переходит между ними клавишей Tab и работает с тем, на котором находится фокус. Какие клавиши до них доходят, описано в разделе Фокус клавиатуры и горячие клавиши.
Откройте панель с focus: true, чтобы она попыталась получить фокус клавиатуры. Вводимые буквы попадают в Input, как только на нём оказывается фокус. Как выбрать поле, которое получит фокус при открытии панели, описано в разделе Горячая клавиша и первый фокус.
Button
Кнопка вызывает onPress. В этом примере показаны кнопка по умолчанию, кнопка plain с горячей клавишей и приглушённая кнопка:
Box({
flexDirection: 'column',
children: [
Button({ key: 'save', label: 'Save', onPress: noop }),
Button({ key: 'next', label: 'Next', hotkey: 'n', plain: true, onPress: noop }),
Button({ key: 'skip', label: 'Skip', dimColor: true, onPress: noop }),
],
})

Кнопка с фокусом отрисовывается в инверсных цветах. Здесь пользователь дважды нажал Tab:

Input
Input — это текстовое поле, которое по умолчанию содержит одну строку и вызывает onSubmit, когда пользователь нажимает Enter:
Input({
key: 'title',
label: 'Title',
placeholder: 'Type a title and press Enter',
value: '',
submitLabel: 'save',
onSubmit: noop,
})
Без фокуса поле показывает подпись и текст-заполнитель:

С фокусом подпись становится жирной, появляется курсор, а после ⏎ отображается submitLabel:

Ввод заменяет текст-заполнитель:

Задайте для rows значение 2 или больше для поля, которое содержит несколько строк, например для заметки или сообщения коммита:
Input({
key: 'note',
label: 'Note',
placeholder: 'Write a note',
rows: 4,
onSubmit: noop,
})
Строки отрисовывают терминал и приложение Desktop. В расширении VS Code поле содержит одну строку. Для rows требуется Claude Code v2.1.301 или новее. В более ранних версиях поле содержит одну строку.
Поле занимает заданное количество строк, даже если оно пустое, но не больше высоты панели или полосы, в которой оно отрисовано. Пока на поле находится фокус, более длинный текст прокручивается внутри него.
- В терминале Enter по-прежнему отправляет ввод. Там пользователь начинает новую строку, вводя обратную косую черту и затем нажимая Enter, или нажимая Shift+Enter, если эмулятор терминала это поддерживает. Это те же клавиши, что и в промпте.
- В терминале клавиши Up и Down перемещают между строками поля. С первой и последней строки они переводят к предыдущему или следующему элементу управления.
onSubmitиonInputполучают весь текст, строки которого объединены через\n.
Select
Select позволяет пользователю выбрать один из нескольких вариантов и вызывает onSelect со значением value выбранного варианта:
Select({
key: 'format',
label: 'Format',
value: picked,
options: [
{ value: 'md', label: 'Markdown' },
{ value: 'html', label: 'HTML' },
{ value: 'txt', label: 'Plain text' },
],
onSelect: (value) => {
picked = value
},
})
В закрытом состоянии он показывает подпись и текущий вариант:

В открытом состоянии он показывает список вариантов и выделяет один из них:

После того как пользователь выберет вариант, список закрывается:

Рисование изображений
Raster
Raster — это сетка цветных символьных ячеек для тепловой карты, спарклайна или игрового поля. Его отрисовывает терминал. В этом примере используется функция cellsOf из начального модуля, которая упаковывает ячейки в строку, принимаемую Raster. Подробнее см. в разделе Отрисовка сетки цветных ячеек:
Raster({
key: 'grid',
columns: 3,
rows: 2,
cells: cellsOf([
[['█', 0x2e7d32], ['█', 0xf9a825], ['█', 0xc62828]],
[['█', 0x2e7d32], ['█', 0x2e7d32], ['█', 0xf9a825]],
]),
})

Raster округляет каждый цвет до более ограниченной палитры, поэтому 0x2e7d32 отрисовывается как #337733.
Svg
Svg отрисовывает SVG-документ в приложении Desktop и расширении VS Code:
Svg({
alt: 'Three bars of rising height',
width: 120,
height: 60,
source:
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 60"><rect x="10" y="40" width="20" height="20" fill="#2e7d32"/><rect x="50" y="25" width="20" height="35" fill="#f9a825"/><rect x="90" y="5" width="20" height="55" fill="#c62828"/></svg>',
})
В терминале панель, которая возвращает только Svg, открывается пустой. Чтобы отрисовать там что-то другое, проверьте e.surface и верните другое дерево.
Image и Client
Для ещё двух элементов примеров здесь нет. Image отрисовывает PNG или необработанные пиксели в терминале. Client — это область, которую отрисовывает ваш второй файл, для анимации и ввода указателем. Их свойства перечислены в справочнике по элементам.
Image отрисовывается как картинка в следующих терминалах:
- kitty 0.28 или новее
- Ghostty
- iTerm2 3.5 или новее. Для отрисовки в iTerm2 требуется Claude Code v2.1.305 или новее.
В любом другом терминале пользователь увидит вместо картинки приглушённый текст alt элемента Image. Пишите текст alt, который понятен сам по себе, поскольку он также отображается, помимо прочего, в следующих случаях:
- GNU screen: сессия, запущенная внутри screen, в любом терминале.
- tmux: сессия, запущенная внутри tmux, для которой не выполнено одно из требований для отрисовки внутри tmux.
- Фоновые сессии: любая фоновая сессия, из какого бы терминала к ней ни подключались.
- iTerm2 без полноэкранной отрисовки: в iTerm2 картинка отрисовывается только при полноэкранной отрисовке и не отрисовывается, если для
CLAUDE_CODE_ALT_SCREEN_FULL_REPAINTустановлено значение1. Чтобы увидеть картинку, выполните/tui fullscreenв промпте Claude Code и не устанавливайте эту переменную. - Путь к файлу в качестве источника в iTerm2 или tmux: в iTerm2 и внутри tmux элемент
Image, у которогоsourceуказываетfile, показывает текстaltвместо картинки. Если у вашего мода есть пользователи iTerm2 или tmux, передавайте картинку в base64 вsource.pngилиsource.rgba, а не как путь вsource.file.
Если пользователи вашего мода видят приглушённый текст в терминале, который отрисовывает изображения протокола графики kitty с плейсхолдерами Unicode, они могут установить для CLAUDE_CODE_FORCE_TERMINAL_IMAGES значение 1. Не следует устанавливать её внутри GNU screen, внутри tmux старше 3.3, во всплывающем окне tmux или при выключенной опции tmux allow-passthrough. В этих случаях пользователи не увидят картинку, а вместо текста alt увидят рамку.
Отрисовка Image внутри tmux
Если Image показывает текст alt внутри tmux, проверьте следующие требования, а также другие случаи отображения текста alt, например фоновую сессию:
- Claude Code v2.1.310 или новее
- tmux 3.3 или новее
- Claude Code запущен в панели tmux, а не во всплывающем окне tmux
- tmux запущен внутри kitty 0.28 или новее, Ghostty или iTerm2 3.5 или новее
- Опции tmux
focus-eventsиallow-passthroughимеют значениеon. Внутри kitty или Ghosttyallow-passthroughтакже может иметь значениеall. - Внутри iTerm2 tmux запущен без
-CC, полноэкранная отрисовка включена, аCLAUDE_CODE_ALT_SCREEN_FULL_REPAINTне установлена. - Внутри iTerm2 окно tmux не больше окна iTerm2. Чтобы проверить это, выполните
tmux display-message -p '#{window_bigger}'в этом окне tmux. Если команда выводит1, подгоните размер окна tmux, затем перезапустите Claude Code. - Автор мода передаёт картинку как байты
pngилиrgba, а не как путьfile. Если вы используете мод, который написали не вы, и остальные требования выполнены, попросите его автора проверить это требование.
Для каждой опции tmux, которая ещё не установлена как требуется, выполните соответствующую команду в оболочке:
tmux set -g allow-passthrough on
tmux set -g focus-events on
Затем отключитесь от tmux, подключитесь снова и перезапустите Claude Code. Перезапускайте его снова каждый раз, когда подключаетесь к tmux из другого терминала. Чтобы сохранить обе опции после перезапуска сервера tmux, также добавьте обе строки в ~/.tmux.conf.
Где ещё может отрисовывать мод
Все примеры отрисовываются на панели. Мод также может отрисовывать в других местах и вызывать Claude Code, чтобы тот что-то показал за него:
- Панель и полоса: Выбор места для отрисовки
- Собственные строки Claude Code, например индикатор загрузки: Изменение того, что уже отрисовывает Claude Code
- Всплывающее уведомление, строка состояния и строка лога: Показать что-то, не начиная ход
- Диалог с вопросом: Удержание вызова инструмента до решения пользователя
Дальнейшие шаги
- Отрисовка в интерфейсе: пошаговое создание панели с вкладками
- Тестирование отрисовки: нажатие ваших кнопок из теста
- Справочник по элементам: основные свойства каждого элемента и приложения, которые его отрисовывают