Galeria de interface para mods
Veja os elementos de interface que um mod do Claude Code pode desenhar, como texto, botões, campos, Markdown, código e diffs, com código de exemplo e capturas de tela do terminal.
Um mod desenha sua interface a partir de elementos: texto, caixas, botões, campos e alguns que formatam o conteúdo para você. Os exemplos aqui mostram o código que desenha um elemento, e a maioria vem com uma captura de tela do resultado em um painel do terminal, para que você possa escolher um elemento pela aparência.
Para aprender como o desenho funciona, comece com Desenhar na interface. Para as principais props e quais aplicativos desenham cada elemento, consulte a referência de elementos. As declarações de tipo listam todas as props.
Experimentar um exemplo
Os exemplos nesta página são trechos, não mods inteiros. Cada um é o código de um elemento e de tudo o que está aninhado dentro dele.
Para ver um exemplo no seu próprio terminal, crie o pequeno mod destas etapas e cole o exemplo nele. O mod adiciona um comando /gallery que abre um painel e desenha o exemplo ali. Um painel é uma barra lateral ao lado da transcrição em um terminal largo em tela cheia, ou, caso contrário, uma região emoldurada acima do prompt.
1. Criar o mod
Crie um diretório chamado gallery com os diretórios .claude-plugin e hooks dentro dele. Criar um mod explica os arquivos.
Salve o manifesto como gallery/.claude-plugin/plugin.json:
{
"name": "gallery",
"version": "0.1.0",
"description": "Opens a pane that draws one sample",
"author": { "name": "Your Name" }
}
Indique seu ponto de entrada em gallery/hooks/hooks.json:
{
"modules": ["./register.js"]
}
Salve o código como gallery/hooks/register.js. Ele adiciona um comando /gallery que abre um painel e desenha Plain text nesse painel:
// 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. Executar o mod
No seu shell, inicie o Claude Code a partir do diretório que contém gallery:
claude --plugin-dir ./gallery
No prompt do Claude Code, execute /gallery. Um painel é aberto com Plain text nele.
3. Trocar por um exemplo
Copie um exemplo desta página. Em register.js, cole-o sobre Text({ children: ['Plain text'] }), de modo que ele venha depois de return, e salve o arquivo. O Claude Code recarrega o módulo cada vez que você salva, então execute /gallery novamente para ver o novo exemplo.
Escolher um elemento
Os exemplos estão agrupados pelo que você quer colocar na tela:
- Mostrar texto:
Text,MarkdowneLink - Mostrar código e alterações:
Code - Organizar elementos:
Box - Receber entrada:
Button,InputeSelect - Desenhar imagens:
Raster,Svg,ImageeClient
Mostrar texto
Três elementos colocam palavras na tela: Text para o seu próprio estilo, Markdown para conteúdo já formatado e Link para uma URL.
Text
Text desenha uma string com os estilos que você fornece. Este exemplo mostra texto simples e oito estilos, um em cada linha:
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 desenha o texto em cinza. backgroundColor preenche apenas a largura do texto.
Markdown
Markdown formata o texto da mesma forma que as respostas do Claude são formatadas. Passe o conteúdo em text, não em 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',
})

Um título é desenhado em negrito sem suas marcas #. O código inline é desenhado em cor sem seus acentos graves. Uma citação é desenhada em itálico com uma barra à esquerda.
Link
Link desenha um rótulo seguido de sua URL:
Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })

O terminal desenha a URL como texto após o rótulo. Se um clique a abre ou não depende do terminal do usuário.
Mostrar código e alterações
Code desenha texto-fonte com as próprias cores de sintaxe do Claude Code, ou um diff. Na extensão do VS Code, Code mostra seu source como texto simples, sem nenhuma das cores, números de linha ou sombreamento de diff destas capturas de tela.
Code
Indique a language, ou passe um path para que o Claude Code a deduza. Com startLine, as linhas são numeradas a partir desse número:
Code({
language: 'javascript',
startLine: 1,
source: "const name = 'mods'\nconsole.log('hello ' + name)",
})

As cores vêm do tema do usuário.
Code como diff
Com format: 'diff', source é um ou mais hunks de diff unificado:
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.',
})

O Claude Code desenha números de linha no lugar da linha @@. Onde uma linha removida e uma linha adicionada são parecidas, as palavras que mudaram recebem uma sombra mais forte.
Organizar elementos
Box
Box dispõe o que está dentro dele em uma linha ou em uma coluna, e pode desenhar uma borda. Este exemplo coloca uma linha de palavras acima de uma caixa com borda:
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'"] })],
}),
],
})

A borda se estende até a largura do painel.
Receber entrada
Button, Input e Select são controles: o usuário se move entre eles com Tab e usa aquele que tem o foco. Foco do teclado e teclas de atalho explica quais teclas chegam até eles.
Abra um painel com focus: true para solicitar o foco do teclado para ele. As letras digitadas chegam a um Input assim que ele tem o foco. Para escolher qual campo tem o foco quando o painel abre, consulte Definir uma tecla de atalho e o primeiro foco.
Button
Um botão executa onPress. Este exemplo mostra a forma padrão, um botão plain com uma tecla de atalho e um esmaecido:
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 }),
],
})

Um botão que tem o foco é desenhado em vídeo inverso. Aqui o usuário pressionou Tab duas vezes:

Input
Um Input é um campo de texto que, por padrão, contém uma linha e executa onSubmit quando o usuário pressiona Enter:
Input({
key: 'title',
label: 'Title',
placeholder: 'Type a title and press Enter',
value: '',
submitLabel: 'save',
onSubmit: noop,
})
Sem o foco, o campo mostra seu rótulo e seu placeholder:

Com o foco, o rótulo fica em negrito, um cursor aparece e o submitLabel é exibido após ⏎:

Digitar substitui o placeholder:

Defina rows como 2 ou mais para um campo que contém várias linhas, como uma nota ou uma mensagem de commit:
Input({
key: 'note',
label: 'Note',
placeholder: 'Write a note',
rows: 4,
onSubmit: noop,
})
O terminal e o aplicativo Desktop desenham as linhas. Na extensão do VS Code, o campo contém uma linha. rows requer o Claude Code v2.1.301 ou posterior. Em versões anteriores, o campo contém uma linha.
O campo ocupa a quantidade de linhas que você definir, mesmo quando está vazio, até a altura do painel ou da faixa em que é desenhado. Enquanto o campo tem o foco, textos mais longos rolam dentro dele.
- No terminal, Enter ainda envia. Lá, o usuário inicia uma nova linha digitando uma barra invertida e depois pressionando Enter, ou pressionando Shift+Enter onde o emulador de terminal oferece suporte. São as mesmas teclas do prompt.
- No terminal, Para cima e Para baixo movem entre as linhas do campo. A partir da primeira e da última linha, elas movem para o controle anterior ou seguinte.
onSubmiteonInputrecebem o texto inteiro com suas linhas unidas por\n.
Select
Um Select permite que o usuário escolha uma entre várias opções e executa onSelect com o value da opção:
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
},
})
Fechado, ele mostra seu rótulo e a opção atual:

Aberto, ele lista suas opções e marca uma:

Depois que o usuário escolhe uma opção, a lista se fecha:

Desenhar imagens
Raster
Um Raster é uma grade de células de caracteres coloridas, para um mapa de calor, um sparkline ou um tabuleiro de jogo. O terminal o desenha. Este exemplo usa a função cellsOf do módulo inicial, que empacota as células na string que um Raster recebe. Desenhar uma grade de células coloridas explica isso:
Raster({
key: 'grid',
columns: 3,
rows: 2,
cells: cellsOf([
[['█', 0x2e7d32], ['█', 0xf9a825], ['█', 0xc62828]],
[['█', 0x2e7d32], ['█', 0x2e7d32], ['█', 0xf9a825]],
]),
})

Um Raster arredonda cada cor para uma paleta menor, então 0x2e7d32 é desenhado como #337733.
Svg
Um Svg desenha um documento SVG no aplicativo Desktop e na extensão do 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>',
})
No terminal, um painel que retorna apenas um Svg abre vazio. Para desenhar outra coisa ali, verifique e.surface e retorne uma árvore diferente.
Image e Client
Mais dois elementos não têm exemplo aqui. Image desenha um PNG ou pixels brutos no terminal. Client é uma região que um segundo arquivo seu desenha, para animação e entrada de ponteiro. A referência de elementos lista suas props.
Uma Image é desenhada como imagem nestes terminais:
- kitty 0.28 ou posterior
- Ghostty
- iTerm2 3.5 ou posterior. Desenhar no iTerm2 requer o Claude Code v2.1.305 ou posterior.
Em qualquer outro terminal, o usuário vê o texto alt da Image, esmaecido, no lugar da imagem. Escreva um texto alt que faça sentido por si só, porque ele também aparece nestes casos, entre outros:
- GNU screen: uma sessão executada dentro do screen, em qualquer terminal.
- tmux: uma sessão executada dentro do tmux que não atende a um requisito para desenhar dentro do tmux.
- Sessões em segundo plano: toda sessão em segundo plano, independentemente do terminal a partir do qual ela esteja conectada.
- iTerm2 fora da renderização em tela cheia: no iTerm2, a imagem é desenhada apenas sob a renderização em tela cheia, e não enquanto
CLAUDE_CODE_ALT_SCREEN_FULL_REPAINTestiver definida como1. Para ver a imagem, execute/tui fullscreenno prompt do Claude Code e deixe essa variável sem definir. - Uma origem de caminho de arquivo no iTerm2 ou no tmux: no iTerm2 e dentro do tmux, uma
Imagecujasourcenomeia umfilemostra o textoaltem vez da imagem. Se o seu mod tiver usuários do iTerm2 ou do tmux, passe a imagem como base64 emsource.pngousource.rgbaem vez de como caminho emsource.file.
Se os usuários do seu mod virem o texto esmaecido em um terminal que desenha imagens do protocolo gráfico do kitty com placeholders Unicode, eles podem definir CLAUDE_CODE_FORCE_TERMINAL_IMAGES como 1. Eles não devem defini-la dentro do GNU screen, dentro de um tmux anterior à versão 3.3, em um popup do tmux ou com a opção allow-passthrough do tmux desativada. Nesses casos, eles não veem nenhuma imagem e veem uma caixa no lugar do texto alt.
Desenhar uma Image dentro do tmux
Se uma Image mostrar seu texto alt dentro do tmux, verifique estes requisitos junto com os outros casos de texto alt, como uma sessão em segundo plano:
- Claude Code v2.1.310 ou posterior
- tmux 3.3 ou posterior
- O Claude Code é executado em um painel do tmux, não em um popup do tmux
- O tmux é executado dentro do kitty 0.28 ou posterior, do Ghostty ou do iTerm2 3.5 ou posterior
- As opções do tmux
focus-eventseallow-passthroughestão comoon. Dentro do kitty ou do Ghostty,allow-passthroughtambém pode serall. - Dentro do iTerm2, o tmux é executado sem
-CC, a renderização em tela cheia está ativada eCLAUDE_CODE_ALT_SCREEN_FULL_REPAINTnão está definida. - Dentro do iTerm2, a janela do tmux não é maior que a janela do iTerm2. Para verificar, execute
tmux display-message -p '#{window_bigger}'nessa janela do tmux. Se ele imprimir1, ajuste a janela do tmux para caber e, em seguida, reinicie o Claude Code. - O autor do mod passa a imagem como bytes
pngourgba, não como um caminhofile. Se você usa um mod que não escreveu e os outros requisitos são atendidos, peça ao autor que verifique este.
Para cada opção do tmux que ainda não esteja definida conforme exigido, execute o comando correspondente no seu shell:
tmux set -g allow-passthrough on
tmux set -g focus-events on
Em seguida, desconecte-se do tmux, conecte-se novamente e reinicie o Claude Code. Reinicie-o novamente sempre que conectar o tmux a partir de um terminal diferente. Para manter ambas as opções entre reinicializações do servidor tmux, adicione também as duas linhas a ~/.tmux.conf.
Ver onde um mod pode desenhar
Todos os exemplos desenham em um painel. Um mod também pode desenhar em outros lugares e chamar o Claude Code para mostrar algo por ele:
- Painel e faixa: Escolher onde desenhar
- As próprias linhas do Claude Code, como o spinner: Alterar o que o Claude Code já desenha
- Toast, linha de status e linha de log: Mostrar algo sem iniciar um turno
- Diálogo de pergunta: Reter uma chamada de ferramenta até que o usuário decida
Próximos passos
- Desenhar na interface: construa um painel com abas, passo a passo
- Testar um desenho: pressione seus botões a partir de um teste
- Referência de elementos: as principais props de cada elemento e os aplicativos que o desenham