Shortcuts Dialog
blocklayoutLinear-style keyboard reference sheet: a '?' dialog listing shortcut groups (label, description, Kbd combo) in a responsive two-column grid. Ships a built-in trigger button, controlled/uncontrolled open, custom groups via prop, and an Esc footer hint. Display only — wire real handlers in your app.
Installation
$pnpm dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/shortcuts-dialog.json$npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/shortcuts-dialog.json$yarn dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/shortcuts-dialog.json$bunx shadcn-svelte@latest add https://uipkge.dev/r/svelte/shortcuts-dialog.jsonManifest:
https://uipkge.dev/r/svelte/shortcuts-dialog.jsonInstalls to:src/lib/components/blocks/shortcuts-dialog/Variants
Loading interactive previews…
Loading interactive previews…
npm dependencies
Files installed (1)
src/lib/components/blocks/shortcuts-dialog/ShortcutsDialog.svelte4.5 kB
<script lang="ts" module> import type { Snippet } from 'svelte' export interface Shortcut { keys: string[] description: string } export interface ShortcutGroup { label: string shortcuts: Shortcut[] } export interface ShortcutsDialogProps { groups?: ShortcutGroup[] /** Render the built-in trigger button. */ trigger?: boolean /** * Custom trigger content. Receives the trigger `props` (open handler, * a11y attributes) — spread them onto your element. Used only when * `trigger` is false. */ triggerSnippet?: Snippet<[{ props: Record<string, unknown> }]> /** Show the 'Press Esc to close' footer hint. */ footer?: boolean /** Controlled open state. Omit for uncontrolled (internal state). */ open?: boolean onOpenChange?: (open: boolean) => void class?: string } </script> <script lang="ts"> import { Keyboard } from '@lucide/svelte' import { cn } from '$lib/utils' import { Button } from '$lib/components/ui/button' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '$lib/components/ui/dialog' import { Kbd } from '$lib/components/ui/kbd' let { groups = [ { label: 'Navigation', shortcuts: [ { keys: ['G', 'I'], description: 'Go to inbox' }, { keys: ['G', 'D'], description: 'Go to drafts' }, { keys: ['⌘', 'K'], description: 'Open command menu' }, { keys: ['⌥', '↑', '↓'], description: 'Move between items' }, ], }, { label: 'Actions', shortcuts: [ { keys: ['C'], description: 'Compose new' }, { keys: ['/'], description: 'Focus search' }, { keys: ['⌘', 'S'], description: 'Save changes' }, { keys: ['E'], description: 'Archive selection' }, ], }, { label: 'General', shortcuts: [ { keys: ['?'], description: 'Show this dialog' }, { keys: ['⇧', '?'], description: 'Show cheat sheet' }, { keys: ['Esc'], description: 'Close dialogs' }, ], }, ], trigger = true, triggerSnippet, footer = true, open = $bindable(undefined), onOpenChange, class: className, }: ShortcutsDialogProps = $props() // Local state drives the uncontrolled case; the `open` prop takes precedence. let internalOpen = $state(false) const isOpen = $derived(open ?? internalOpen) function handleOpenChange(value: boolean) { internalOpen = value open = value onOpenChange?.(value) } </script> <!-- Dialog renders only its children, so the slot marker lives on a layout-free wrapper. --> <div data-slot="shortcuts-dialog" class="contents"> <Dialog open={isOpen} onOpenChange={handleOpenChange}> {#if trigger} <DialogTrigger> {#snippet child({ props })} <Button variant="outline" size="sm" {...props}> <Keyboard aria-hidden="true" /> Shortcuts <Kbd>?</Kbd> </Button> {/snippet} </DialogTrigger> {:else if triggerSnippet} <DialogTrigger> {#snippet child({ props })} {@render triggerSnippet({ props })} {/snippet} </DialogTrigger> {/if} <DialogContent class={cn('max-w-lg', className)}> <DialogHeader> <DialogTitle>Keyboard shortcuts</DialogTitle> <DialogDescription>Move faster without leaving the keyboard.</DialogDescription> </DialogHeader> <div class="grid max-h-[60vh] gap-x-8 gap-y-6 overflow-y-auto pr-1 sm:grid-cols-2"> {#each groups as group (group.label)} <div class="space-y-2"> <p class="text-muted-foreground text-xs font-medium tracking-widest uppercase">{group.label}</p> <ul class="divide-y"> {#each group.shortcuts as shortcut (shortcut.description)} <li class="flex items-center justify-between gap-4 py-1.5"> <span class="text-sm">{shortcut.description}</span> <span class="flex shrink-0 items-center gap-1"> {#each shortcut.keys as key (key)} <Kbd>{key}</Kbd> {/each} </span> </li> {/each} </ul> </div> {/each} </div> {#if footer} <DialogFooter class="justify-start"> <p class="text-muted-foreground flex items-center gap-1.5 text-xs">Press <Kbd>Esc</Kbd> to close</p> </DialogFooter> {/if} </DialogContent> </Dialog> </div>
Raw manifest:https://uipkge.dev/r/svelte/shortcuts-dialog.json