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 de uma linha que 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:

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:
- tmux e screen: uma sessão executada dentro do tmux ou do screen, em qualquer terminal.
- 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: o iTerm2 desenha uma
Imagecuja propsourcecontém bytespngourgba, e mostra o textoaltpara uma cujasourcenomeia umfile. Se o seu mod tiver usuários do iTerm2, 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. Dentro do tmux ou do screen isso não ajuda: o texto alt desaparece, e o Claude Code envia a imagem sem encapsulá-la para o passthrough do tmux ou do screen.
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