Follow Discord
Sweep 10 Nov 2026 · 02:18Z Build v2.1.322 539 read Stable v2.1.311 Latest v2.1.322 Next v2.1.322 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-code

Draw in the interface with a mod changedplugins/mods/interface

Nearest release: v2.1.321, published an hour before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 9 Nov 2026 21:00 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 9 Nov 2026 21:07 UTC.

Upstream edited
Recorded here
Lines+87added
Lines−0removed
From line 193 where the diff opens
First seen 1 Oct 2026 this site's first read of the page
Recorded edits30to this page, all time

### Place a row in the transcript ### Put a backdrop behind the conversation

The whole hunk

from line 193, old and new numbered
/
lines
from line 193
193193>
194194> To draw in the band, filter on `{ component: 'AbovePrompt' }`.
195195 
196A mod can also [place a row of its own in the transcript](#place-a-row-in-the-transcript).
197 
196198### Change what Claude Code already draws
197199 
198200Claude Code draws most of its interface itself: messages, tool call rows, the spinner, and more. Each of those parts is a render site too, so a mod can restyle or replace it. To change one, filter your `ui.render` hook on its name from this table:
from line 346
344346* **The question dialog**: at `AskUserQuestion`, the panel keeps its own question card and draws your elements above it. Props you pass to `next` don't change the card.
345347* **Prompt suggestions**: `$.prompt.suggest` resolves with `isShown: false` and shows nothing, because the panel keeps the prompt box's dim suggestion text for Claude's own suggestions.
346348* **Text limits**: the panel cuts a status line at 200 characters or two rows, and a toast at 500 characters.
349 
350### Place a row in the transcript
351 
352A row is a line your mod adds to the transcript in the terminal, after the latest message. It stays at that spot as the conversation goes on, and Claude doesn't see it. `$.ui.place` requires Claude Code v2.1.314 or later.
353 
354**1. Place the row**
355 
356Call [`$.ui.place`](https://code.claude.com/docs/en/plugins/mods/reference#mods-api-methods) with an `id`. The `id` is a name you make up for the row, such as `build-status`. It can be 1 to 64 letters, digits, `_`, or `-`, and each row your mod has in the transcript needs its own.
357 
358**2. Draw the row**
359 
360Draw the row at the [`Placed`](https://code.claude.com/docs/en/plugins/mods/reference#render-sites) render site.
361 
362This example adds a `/build-status` command. When the user runs the command, the mod adds a row that shows `Build: passing`. The text is fixed to keep the example short, so a real mod would draw its own result:
363 
364```javascript theme={null}
365export function register(on) {
366 on('session.start', async ($, e, next) => {
367 await $.command.register({ name: 'build-status', description: 'Show the build status' })
368 return next(e)
369 })
370 
371 on('command.run', { command: 'build-status' }, async ($) => {
372 const placed = await $.ui.place({ id: 'build-status' })
373 // Where nothing draws the row, reply with text instead
374 return placed.isPlaced ? {} : { text: 'Build: passing' }
375 })
376 
377 on('ui.render', { component: 'Placed' }, async ($, e, next) => {
378 // This hook runs for every mod's rows, and another mod can use the same id
379 if (e.props.plugin !== $.plugin.name || e.props.id !== 'build-status') return next(e)
380 const { Text } = $.ui.resolve(e)
381 return Text({ children: ['Build: passing'] })
382 })
383}
384```
385 
386To try the example, put this code in a [mod](https://code.claude.com/docs/en/plugins/mods/create.md). In a terminal session, run `/build-status` at the Claude Code prompt. `Build: passing` appears as a row at the end of the transcript.
387 
388The call doesn't always show a row, and a row can go away later, so handle these cases in your mod:
389 
390* **The result**: `{ isPlaced: true, requestId }` when the terminal draws the row. Otherwise `isPlaced` is `false` and `reason` says why, as in `no attached surface draws placed rows yet`. One reason is the [limit on rows](https://code.claude.com/docs/en/plugins/mods/reference.md#limits) a mod can have at one time.
391* **A second call with the same `id`**: while the first row is still in the transcript, the call adds no row and resolves with that row's `requestId`. To change what the row shows, [redraw the row](#redraw-when-something-changes).
392* **When the row goes away**: when the conversation ends, when the user rewinds past the row, or, outside [fullscreen rendering](https://code.claude.com/docs/en/fullscreen.md), when the conversation is compacted. `--resume` doesn't bring the row back. To show the row again, call `$.ui.place` again.
393 
394### Put a backdrop behind the conversation
395 
396> [!NOTE]
397>
398> `$.theme.set` and `$.theme.clear` replace `$.ui.backdrop`, which Claude Code v2.1.319 removed. Change `$.ui.backdrop({ id: 'your-backdrop' })` to `$.theme.set({ backdrop: { id: 'your-backdrop' } })`, and `$.ui.backdrop(undefined)` to `$.theme.clear()`, which removes any mod's backdrop.
399 
400To put a backdrop behind the conversation in the Desktop app or the mobile app, call [`$.theme.set`](https://code.claude.com/docs/en/plugins/mods/reference#mods-api-methods) with a `backdrop`, then draw the backdrop at the [`Backdrop`](https://code.claude.com/docs/en/plugins/mods/reference#render-sites) render site. To take the backdrop off, call `$.theme.clear()`. The terminal draws no backdrop. `$.theme.set` and `$.theme.clear` require Claude Code v2.1.319 or later.
401 
402This mod sets a backdrop when the session starts, draws the backdrop, and adds a `/plain` command that takes the backdrop off:
403 
404```javascript theme={null}
405export function register(on) {
406 // Neither a reload of this mod nor --resume keeps the backdrop, so set it here
407 on('session.start', async ($, e, next) => {
408 await $.theme.set({ backdrop: { id: 'night-sky', colorScheme: 'dark' } })
409 await $.command.register({ name: 'plain', description: 'Take the backdrop off' })
410 return next(e)
411 })
412 
413 on('ui.render', { component: 'Backdrop' }, async ($, e, next) => {
414 // This hook runs for every mod's backdrop, and another mod can use the same id
415 if (e.props.plugin !== $.plugin.name || e.props.id !== 'night-sky') return next(e)
416 const { Box, Text } = $.ui.resolve(e)
417 return Box({ backgroundColor: 'blue', children: [Text({ children: ['Night sky'] })] })
418 })
419 
420 on('command.run', { command: 'plain' }, async ($) => {
421 const cleared = await $.theme.clear()
422 return { text: cleared.reason }
423 })
424}
425```
426 
427To try the example, put this code in a [mod](https://code.claude.com/docs/en/plugins/mods/create.md) and start a session in the Desktop app or the mobile app. To take the backdrop off, run `/plain` at the Claude Code prompt. The transcript shows `the theme is cleared` after the mod's name, as in `night-sky: the theme is cleared` for a mod named `night-sky`.
428 
429Check what `backdrop` takes, what the call's result tells you, and what other mods can change:
430 
431* **The `backdrop` fields**: `id`, a [name](https://code.claude.com/docs/en/plugins/mods/reference.md#limits) you choose, is required, and the other fields are optional. `colorScheme` is `'light'` or `'dark'` and says whether your drawing is light or dark. For `glass`, see [the types for your build](https://code.claude.com/docs/en/plugins/mods/create.md#get-the-types-for-your-build).
432* **Whether the backdrop is drawn**: `$.theme.set` resolves with `isDrawn: true` when a Desktop or mobile app connected to the session says it draws backdrops. Otherwise `isDrawn` is `false` and `reason` says why.
433* **One backdrop for each session**: a `$.theme.set` call replaces the session's backdrop and `$.theme.clear()` removes that backdrop, whichever mod set it. Call `$.theme.clear()` only when the user asks for it.
347434 
348435## Build a tree from elements
349436 
Feedback