shadcn.io is not affiliated with official shadcn/ui
OAuth Scopes Command Menu Block for Radix UI
A developer portal's command menu shown open on an authorisation page: nine scopes in three groups with a Low, Medium or High risk word, Read-only and Everything presets, and a second Enter for high-risk ones.
Installation
Overview
Choose what an app may do with this OAuth scopes command menu for React with Radix UI. It opens from the authorisation page of Grantgate, a developer portal, whose header holds an outline field with its ⌘ K cap, and the page is drawn under a soft scrim inside a hairline frame with a plus mark on each corner, asking whether Shiptrail CLI may access the account. The menu is the catalog Command over nine scopes in three groups, Repositories, Profile and Billing, each a drawn checkbox, a name, its key and a risk word: Low, Medium or High. Enter grants or revokes the highlighted scope and the menu stays open. A High scope asks first, the row turning to "Grant it?", and takes a second Enter on the same row; Escape cancels the question. Two Button presets above the field set the whole selection: Read-only grants the four read scopes, and Everything grants all nine, asking the same way because two of them are High. The foot counts "5 granted, 1 high risk", and the drawn page lists in words what the tool would be allowed to do. 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 scopes and query. For developer portals, API consoles and any consent screen with a long list of permissions.
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 the authorisation page, 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 scope you granted in the copy is there 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 does the second Enter work?
Enter on a High scope that is off does not grant it: it marks the row as waiting, shows "Grant it?" at its end, and the status line explains. A second Enter on the same row grants it. Anything else drops the question: typing, Escape (the first Escape cancels the question and only the next one closes the menu), or pressing another row, which starts that row's own question if it is High. Revoking never asks, because taking access away is the safe direction.
What do the presets do?
Read-only replaces the selection with the scopes whose key ends in :read: four of them, none High. Everything grants all nine, so it asks first, like a High scope: the first press turns its label into "Grant all nine?" and the second grants. Both buttons keep their width while the label changes, so nothing moves. They set the selection, they do not add to it.
Where does the risk word come from?
It is typed with each scope, 1 to 3, as Low, Medium or High, and the foot's "high risk" count is derived from the scopes that are granted and High, never typed twice. Risk is a word and, for High, a warning icon in the foreground colour, not a colour, so it reads the same in every theme and to every reader. In your app take the level from your scope registry.
What stays local, and how do I wire it?
All of it. Nothing is granted: the scopes are state in the block, and each status line says "In this demo only" or that nothing was changed anywhere. In your app send the final selection from the consent page's own Authorise button, not from the menu, and keep the High confirmation on the server too.
Is it accessible from the keyboard?
Yes. Type to search the names, keys and a few hidden words, the arrow keys move through the rows, Enter grants or revokes, and Escape cancels a waiting question before it closes the menu with focus on the field. The presets are ordinary buttons above the field. Ctrl or ⌘ K opens the dialog while focus is inside the block, and only then. The rows are options of a cmdk listbox; the block turns off its own fuzzy filter and lists the rows itself.