Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Recipient Tokens Command Menu Block for Svelte

An email client's command menu hung under a compose window's To field: ten contacts in Frequent and Everyone else groups, removable recipient tokens, Backspace to take the last back, and a typed address that adds itself.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Fill a To field from the keyboard with this recipient command menu for Svelte with Ark UI. It opens from a new message in Letterloom, an email client, whose header holds an outline field with its ⌘ K cap, and the compose window is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The menu is the catalog Command hung under the drawn To field: ten contacts in Frequent and Everyone else groups, each with an initials Avatar, an address and a presence word. Choosing a contact adds a removable token above the field, the row reads Added with a tick, and the menu stays open so you can add the next; Backspace on the empty field takes the last token back, and a typed address that is not a contact adds a first row that Enter chooses. The tokens are real buttons, the drawn To field behind the menu mirrors them, and nothing is sent. For preview the menu is drawn open in place when the page loads; the field, or Ctrl or ⌘ K while focus is in the block, opens the real command dialog with the same contacts, tokens and query. For mail, invitations, sharing sheets and any field that takes several people.

FAQ

Why is the menu already open, and what do I keep?

So you can see it without a click. On load the menu is the Command drawn inline over a picture of a compose window, in a plain shell that is not modal, so nothing is trapped, hidden or focused and the page around the preview keeps working. The header's field opens the real command dialog, modal, with its focus trap, Escape and focus return, and the inline copy stays closed until a reload. Both show the same Palette and share the block's state, so a token or a typed address in the copy is in the dialog. In your app keep the dialog and drop the copy: the "in-place" state, the scrim with its shell and the Escape and blur effects.

How do the tokens work?

Each recipient is a button in a list labelled Recipients, named "Remove Ottilie Vanterpool", so a pointer or Tab and Enter removes it. The band above the field holds at least one line, wraps on a phone and scrolls past about three lines, so the list below shrinks instead of the menu growing. Choosing a contact that is already a token removes it, which the status line says, and the row's Added tick follows.

What does Backspace do?

On an empty field it removes the last token, and the status line says whom it removed and how many recipients are left. With text in the field it edits the text as usual. The key is handled by a capture listener on the menu, so the library never sees it, and with no tokens left it says there is nothing to remove.

How does a typed address become a recipient?

When the field holds something shaped like an address (text, an @, a domain) that is neither a contact nor already a token, a row "Add" with the address comes first, highlighted, and Enter adds it as a token named by the address. A half-typed address shows no row, and the empty state tells you to type the whole address. The check is a simple pattern, so validate on your server too.

What stays local, and how do I wire it?

All of it. The ten contacts, their addresses and their presence are typed constants and nothing is sent anywhere. In your app fill CONTACTS from your address book, load presence from your service, and read the tokens from chosen into your message when it is sent. Presence is a word because colour alone would not say it.

Is it accessible from the keyboard?

Yes. Type to search, the arrow keys move through the rows, Enter adds or removes a contact, Backspace on the empty field removes the last token, and Tab reaches each token's remove button. Escape closes the menu with focus on the field, and Ctrl or ⌘ K opens the dialog while focus is inside the block, and only then. The rows are options of a combobox and the first is highlighted when it opens.