Galerie d'interface pour les mods
Découvrez les éléments d'interface qu'un mod Claude Code peut dessiner, comme du texte, des boutons, des champs, du Markdown, du code et des diffs, avec des exemples de code et des captures d'écran du terminal.
Un mod dessine son interface à partir d'éléments : du texte, des boîtes, des boutons, des champs, et quelques éléments qui mettent en forme le contenu pour vous. Les exemples présentés ici montrent le code qui dessine un élément, et la plupart sont accompagnés d'une capture d'écran du résultat dans un panneau du terminal, afin que vous puissiez choisir un élément selon son apparence.
Pour comprendre le fonctionnement du dessin, commencez par Dessiner dans l'interface. Pour les principales props et les applications qui dessinent chaque élément, consultez la référence des éléments. Les déclarations de types répertorient toutes les props.
Essayer un exemple
Les exemples de cette page sont des extraits, et non des mods complets. Chacun correspond au code d'un élément et de tout ce qui y est imbriqué.
Pour voir un exemple dans votre propre terminal, créez le petit mod décrit dans ces étapes et collez-y l'exemple. Le mod ajoute une commande /gallery qui ouvre un panneau et y dessine l'exemple. Un panneau est une barre latérale à côté de la transcription dans un terminal large en plein écran, ou sinon une zone encadrée au-dessus du prompt.
1. Créer le mod
Créez un répertoire nommé gallery contenant les répertoires .claude-plugin et hooks. Créer un mod explique les fichiers.
Enregistrez le manifeste sous gallery/.claude-plugin/plugin.json :
{
"name": "gallery",
"version": "0.1.0",
"description": "Opens a pane that draws one sample",
"author": { "name": "Your Name" }
}
Indiquez votre point d'entrée dans gallery/hooks/hooks.json :
{
"modules": ["./register.js"]
}
Enregistrez le code sous gallery/hooks/register.js. Il ajoute une commande /gallery qui ouvre un panneau, et dessine Plain text dans ce panneau :
// 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. Exécuter le mod
Dans votre shell, démarrez Claude Code depuis le répertoire qui contient gallery :
claude --plugin-dir ./gallery
Dans le prompt de Claude Code, exécutez /gallery. Un panneau s'ouvre et affiche Plain text.
3. Remplacer par un exemple
Copiez un exemple de cette page. Dans register.js, collez-le à la place de Text({ children: ['Plain text'] }), de sorte qu'il suive return, puis enregistrez le fichier. Claude Code recharge le module à chaque enregistrement : exécutez donc à nouveau /gallery pour voir le nouvel exemple.
Choisir un élément
Les exemples sont regroupés selon ce que vous souhaitez afficher à l'écran :
- Afficher du texte :
Text,MarkdownetLink - Afficher du code et des modifications :
Code - Disposer des éléments :
Box - Recueillir une saisie :
Button,InputetSelect - Dessiner des images :
Raster,Svg,ImageetClient
Afficher du texte
Trois éléments affichent des mots à l'écran : Text pour votre propre mise en forme, Markdown pour un contenu déjà formaté, et Link pour une URL.
Text
Text dessine une chaîne avec les styles que vous lui donnez. Cet exemple affiche du texte brut et huit styles, un par ligne :
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 dessine le texte en gris. backgroundColor ne remplit que la largeur du texte.
Markdown
Markdown met en forme le texte de la même manière que les réponses de Claude. Transmettez le contenu dans text, et non dans 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',
})

Un titre s'affiche en gras sans ses marques #. Le code en ligne s'affiche en couleur sans ses backticks. Une citation s'affiche en italique avec une barre à sa gauche.
Link
Link dessine un libellé suivi de son URL :
Link({ href: 'https://code.claude.com/docs', label: 'Claude Code docs' })

Le terminal dessine l'URL sous forme de texte après le libellé. La possibilité de l'ouvrir d'un clic dépend du terminal de l'utilisateur.
Afficher du code et des modifications
Code dessine du texte source avec les couleurs syntaxiques propres à Claude Code, ou un diff. Dans l'extension VS Code, Code affiche son source en texte brut, sans les couleurs, les numéros de ligne ni l'ombrage de diff visibles sur ces captures d'écran.
Code
Indiquez le language, ou transmettez un path à partir duquel Claude Code le déduira. Avec startLine, les lignes sont numérotées à partir de ce nombre :
Code({
language: 'javascript',
startLine: 1,
source: "const name = 'mods'\nconsole.log('hello ' + name)",
})

Les couleurs proviennent du thème de l'utilisateur.
Code sous forme de diff
Avec format: 'diff', source contient un ou plusieurs blocs de diff unifié :
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 dessine des numéros de ligne à la place de la ligne @@. Lorsqu'une ligne supprimée et une ligne ajoutée se ressemblent, les mots modifiés reçoivent une teinte plus prononcée.
Disposer des éléments
Box
Box dispose son contenu en ligne ou en colonne, et peut dessiner une bordure. Cet exemple place une ligne de mots au-dessus d'une boîte avec bordure :
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'"] })],
}),
],
})

La bordure s'étend sur toute la largeur du panneau.
Recevoir des saisies
Button, Input et Select sont des contrôles : l'utilisateur passe de l'un à l'autre avec Tab et utilise celui qui a le focus. Focus clavier et raccourcis clavier indique quelles touches leur parviennent.
Ouvrez un panneau avec focus: true pour demander le focus clavier pour celui-ci. Les lettres saisies parviennent à un Input dès qu'il a le focus. Pour choisir quel champ a le focus à l'ouverture du panneau, consultez Définir un raccourci clavier et le premier focus.
Button
Un bouton exécute onPress. Cet exemple montre la forme par défaut, un bouton plain avec un raccourci clavier, et un bouton atténué :
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 }),
],
})

Un bouton qui a le focus s'affiche en vidéo inverse. Ici, l'utilisateur a appuyé deux fois sur Tab :

Input
Un Input est un champ de texte qui contient une ligne par défaut et exécute onSubmit lorsque l'utilisateur appuie sur Enter :
Input({
key: 'title',
label: 'Title',
placeholder: 'Type a title and press Enter',
value: '',
submitLabel: 'save',
onSubmit: noop,
})
Sans le focus, le champ affiche son libellé et son texte indicatif :

Avec le focus, le libellé passe en gras, un curseur apparaît et le submitLabel s'affiche après ⏎ :

La saisie remplace le texte indicatif :

Définissez rows sur 2 ou plus pour un champ qui contient plusieurs lignes, comme une note ou un message de commit :
Input({
key: 'note',
label: 'Note',
placeholder: 'Write a note',
rows: 4,
onSubmit: noop,
})
Le terminal et l'application Desktop affichent les lignes. Dans l'extension VS Code, le champ contient une seule ligne. rows nécessite Claude Code v2.1.301 ou une version ultérieure. Sur les versions antérieures, le champ contient une seule ligne.
Le champ occupe le nombre de lignes que vous définissez, même lorsqu'il est vide, dans la limite de la hauteur du panneau ou de la bande dans laquelle il est affiché. Tant que le champ a le focus, un texte plus long défile à l'intérieur.
- Dans le terminal, Enter soumet toujours. L'utilisateur y commence une nouvelle ligne en tapant une barre oblique inverse puis en appuyant sur Enter, ou en appuyant sur Shift+Enter lorsque l'émulateur de terminal le prend en charge. Ce sont les mêmes touches que dans le prompt.
- Dans le terminal, les flèches Haut et Bas permettent de passer d'une ligne à l'autre du champ. Depuis sa première et sa dernière ligne, elles passent au contrôle précédent ou suivant.
onSubmitetonInputreçoivent l'intégralité du texte, avec ses lignes jointes par\n.
Select
Un Select permet à l'utilisateur de choisir une option parmi plusieurs, et exécute onSelect avec la value de l'option :
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
},
})
Fermé, il affiche son libellé et l'option actuelle :

Ouvert, il liste ses options et en met une en évidence :

Une fois que l'utilisateur a choisi une option, la liste se ferme :

Dessiner des images
Raster
Un Raster est une grille de cellules de caractères colorées, pour une carte de chaleur, une sparkline ou un plateau de jeu. Le terminal la dessine. Cet exemple utilise la fonction cellsOf du module de départ, qui regroupe les cellules dans la chaîne attendue par un Raster. Dessiner une grille de cellules colorées l'explique :
Raster({
key: 'grid',
columns: 3,
rows: 2,
cells: cellsOf([
[['█', 0x2e7d32], ['█', 0xf9a825], ['█', 0xc62828]],
[['█', 0x2e7d32], ['█', 0x2e7d32], ['█', 0xf9a825]],
]),
})

Un Raster arrondit chaque couleur à une palette plus restreinte : 0x2e7d32 s'affiche donc en #337733.
Svg
Un Svg dessine un document SVG dans l'application Desktop et l'extension 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>',
})
Dans le terminal, un panneau qui ne renvoie qu'un Svg s'ouvre vide. Pour y dessiner autre chose, vérifiez e.surface et renvoyez une arborescence différente.
Image et Client
Deux autres éléments n'ont pas d'exemple ici. Image dessine un PNG ou des pixels bruts dans le terminal. Client est une zone dessinée par un second fichier de votre part, pour l'animation et la saisie au pointeur. La référence des éléments répertorie leurs props.
Une Image s'affiche sous forme d'image dans ces terminaux :
- kitty 0.28 ou ultérieur
- Ghostty
- iTerm2 3.5 ou ultérieur. L'affichage dans iTerm2 nécessite Claude Code v2.1.305 ou ultérieur.
Dans tout autre terminal, l'utilisateur voit le texte alt de l'Image, atténué, à la place de l'image. Rédigez un texte alt qui se suffit à lui-même, car il s'affiche aussi dans les cas suivants, entre autres :
- GNU screen : une session exécutée dans screen, dans n'importe quel terminal.
- tmux : une session exécutée dans tmux qui ne remplit pas une condition requise pour dessiner dans tmux.
- Sessions en arrière-plan : toute session en arrière-plan, quel que soit le terminal depuis lequel elle est rattachée.
- iTerm2 hors rendu plein écran : dans iTerm2, l'image ne s'affiche qu'avec le rendu plein écran, et pas lorsque
CLAUDE_CODE_ALT_SCREEN_FULL_REPAINTest défini sur1. Pour voir l'image, exécutez/tui fullscreendans le prompt de Claude Code et laissez cette variable non définie. - Une source par chemin de fichier dans iTerm2 ou tmux : dans iTerm2 et dans tmux, une
Imagedont lasourcedésigne unfileaffiche le textealtau lieu de l'image. Si votre mod a des utilisateurs d'iTerm2 ou de tmux, transmettez l'image en base64 danssource.pngousource.rgbaplutôt que sous forme de chemin danssource.file.
Si les utilisateurs de votre mod voient le texte atténué dans un terminal qui affiche les images du protocole graphique kitty avec des espaces réservés Unicode, ils peuvent définir CLAUDE_CODE_FORCE_TERMINAL_IMAGES sur 1. Ils ne doivent pas la définir dans GNU screen, dans une version de tmux antérieure à 3.3, dans une popup tmux, ni lorsque l'option allow-passthrough de tmux est désactivée. Dans ces cas, ils ne voient aucune image, et une case remplace le texte alt.
Dessiner une Image dans tmux
Si une Image affiche son texte alt dans tmux, vérifiez ces conditions ainsi que les autres cas d'affichage du texte alt, comme une session en arrière-plan :
- Claude Code v2.1.310 ou ultérieur
- tmux 3.3 ou ultérieur
- Claude Code s'exécute dans un panneau tmux, et non dans une popup tmux
- tmux s'exécute dans kitty 0.28 ou ultérieur, Ghostty, ou iTerm2 3.5 ou ultérieur
- Les options tmux
focus-eventsetallow-passthroughsont suron. Dans kitty ou Ghostty,allow-passthroughpeut aussi valoirall. - Dans iTerm2, tmux s'exécute sans
-CC, le rendu plein écran est activé etCLAUDE_CODE_ALT_SCREEN_FULL_REPAINTn'est pas définie. - Dans iTerm2, la fenêtre tmux n'est pas plus grande que la fenêtre iTerm2. Pour le vérifier, exécutez
tmux display-message -p '#{window_bigger}'dans cette fenêtre tmux. Si la commande affiche1, ajustez la taille de la fenêtre tmux, puis redémarrez Claude Code. - L'auteur du mod transmet l'image sous forme d'octets
pngourgba, et non sous forme de cheminfile. Si vous utilisez un mod que vous n'avez pas écrit et que les autres conditions sont remplies, demandez à son auteur de vérifier ce point.
Pour chaque option tmux qui n'est pas déjà définie comme requis, exécutez sa commande dans votre shell :
tmux set -g allow-passthrough on
tmux set -g focus-events on
Détachez-vous ensuite de tmux, rattachez-vous et redémarrez Claude Code. Redémarrez-le à nouveau chaque fois que vous rattachez tmux depuis un autre terminal. Pour conserver les deux options après un redémarrage du serveur tmux, ajoutez aussi les deux lignes à ~/.tmux.conf.
Voir où un mod peut dessiner
Tous les exemples dessinent dans un panneau. Un mod peut aussi dessiner à d'autres endroits, et appeler Claude Code pour afficher quelque chose à sa place :
- Panneau et bandeau : Choisir où dessiner
- Les lignes propres à Claude Code, comme le spinner : Modifier ce que Claude Code dessine déjà
- Toast, barre de statut et ligne de log : Afficher quelque chose sans démarrer un tour
- Boîte de dialogue de question : Suspendre un appel d'outil jusqu'à la décision de l'utilisateur
Étapes suivantes
- Dessiner dans l'interface : créer un panneau avec des onglets, étape par étape
- Tester un dessin : appuyer sur vos boutons depuis un test
- Référence des éléments : les principales props de chaque élément et les applications qui le dessinent