Display

Platform Aware Keys

A platform-aware chord: macOS writes the modifier as ⌘, Windows and Linux write it as Ctrl, because a hint with the wrong glyph reads as a mistake.

  • kbd
  • platform
  • shortcut
  • macos

Preview

1440pxHost theme

Use it with AI

  1. 1. Copy the link.
  2. 2. Write to your agent in your own words and drop the link into the sentence.
  3. 3. The agent opens the link and installs the component from the registry.

put this in the header: https://vibeui.ru/c/kbd-005?lang=en

Open searchWindows и LinuxCtrlK
Show the full instructions

What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.

# Install and place "kbd-005" (Platform Aware Keys) from VibeUI

## 1. Install first — do not skip, do not recreate
Run this exact command before writing any code:
npx shadcn@latest add https://vibeui.ru/r/kbd-005.json

Registry item: https://vibeui.ru/r/kbd-005.json
Installs to: components/vibeui/kbd-005.tsx (the exact path follows this project's components.json aliases).
npm dependencies: none.
Registry dependencies: none.

Install it from the registry. Do not recreate it from the description,
do not substitute a similar component from another library, and do not
rewrite it to match the project's existing style.

## 2. What it is
A platform-aware chord: macOS writes the modifier as ⌘, Windows and Linux write it as Ctrl, because a hint with the wrong glyph reads as a mistake.

A chord that adapts to the system: ⌘ on macOS, Ctrl elsewhere. Zero dependencies, one file, detection in useEffect.

## 3. How to use it
import { Kbd005 } from "@/components/vibeui/kbd-005"

<Kbd005 platform="auto" action="Open search" letter="K" />

Read the installed file for the full prop list.

## 4. Where to place it
This is a small inline component. Put it exactly where the user asked,
inside the existing markup. Do not create a new page, section or
wrapper for it. If a similar control already sits in that spot,
replace it instead of adding a second one.

Placement: ___
(The user fills this line in. If it is still blank, ask where to put it
instead of guessing.)

## 5. Keep exactly as installed
- the local --vibeui-kbd-005-* palette — do not swap it for your theme tokens
- detecting the system after hydration: a value guessed at render time desynchronises the markup
- Ctrl as the starting variant — it is understood on any system, unlike ⌘
- the system caption under the action: without it users cannot tell why the glyph changed
- the kbd tag for keys: a screen reader announces them as input rather than text
- the component's own light surface: keys and captions are dark and vanish on a dark background

## 6. You may change
- the detection mode through platform: auto, mac or windows
- the action name through action
- the chord letter through letter
- the key widths through the --vibeui-kbd-005-* variables

## 7. Rules
- Detection reads the userAgent: it can be spoofed and will miss on rare systems.
- Before hydration the Windows variant is shown — on macOS the glyph swaps once the script loads.
- Linux uses the same Ctrl as Windows: there is no separate branch for it.
- Do not lift the CSS variables into globals.css: the component has to stay a single file.

## 8. Verify
- it renders with no console errors;
- it looks like the preview on the VibeUI page you copied this from;
- if it does not, you changed something listed in section 5 — put it back.

For developers

npx shadcn@latest add https://vibeui.ru/r/kbd-005.json
https://vibeui.ru/r/kbd-005.json

Клиентский компонент: систему определяет useEffect после гидрации, поэтому в файле есть «use client». Сервер не знает системы клиента, и попытка угадать её при рендере даёт рассинхрон разметки — до определения показывается вариант с Ctrl, понятный на любой системе, в отличие от ⌘. Проп platform позволяет отключить автоопределение и зафиксировать вариант для документации. Ширина клавиши модификатора увеличена для ⌘ атрибутом data-system: знак шире буквы, и без правки ряд клавиш выглядит неровным. Подложка светлая: клавиши и подписи тёмные.

Component source

The same file your agent installs. Here in case you would rather copy it by hand.

"use client"

import { useSyncExternalStore } from "react"
import type { ComponentPropsWithoutRef, CSSProperties } from "react"

export type Kbd005Platform = "auto" | "mac" | "windows"

export type Kbd005Props = Omit<ComponentPropsWithoutRef<"div">, "children"> & {
  platform?: Kbd005Platform
  action?: string
  letter?: string
}

// Идея компонента: одно сочетание, разное написание. На macOS модификатор
// пишется знаком ⌘, на Windows и Linux — словом Ctrl, и подсказка с чужим
// знаком читается как ошибка. Платформа определяется после гидрации, а не
// при рендере: сервер не знает системы клиента, и попытка угадать даёт
// рассинхрон разметки. До определения показывается вариант с Ctrl —
// он понятен на любой системе, в отличие от ⌘.
const STYLES = `
:where([data-vibeui-block="kbd-005"]){
--vibeui-kbd-005-surface:oklch(1 0 0);
--vibeui-kbd-005-fg:oklch(0.24 0.014 265);
--vibeui-kbd-005-muted:oklch(0.55 0.014 265);
--vibeui-kbd-005-border:oklch(0.88 0.008 265);
--vibeui-kbd-005-key:oklch(0.975 0.003 265);
--vibeui-kbd-005-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
/* Своя светлая подложка: клавиши и подпись тёмные. */
[data-vibeui-block="kbd-005"]{
display:inline-flex;align-items:center;justify-content:space-between;gap:1.25rem;
box-sizing:border-box;padding:0.75rem 0.875rem;
background:var(--vibeui-kbd-005-surface);
border:1px solid var(--vibeui-kbd-005-border);border-radius:0.875rem;
font-family:var(--vibeui-kbd-005-font);color:var(--vibeui-kbd-005-fg);
font-size:0.8125rem;
}
[data-vibeui-block="kbd-005"] [data-part="text"]{display:flex;flex-direction:column;gap:0.125rem;min-width:0}
[data-vibeui-block="kbd-005"] [data-part="action"]{font-weight:650}
[data-vibeui-block="kbd-005"] [data-part="system"]{font-size:0.6875rem;color:var(--vibeui-kbd-005-muted)}
[data-vibeui-block="kbd-005"] [data-part="keys"]{display:inline-flex;align-items:center;gap:0.25rem;flex:none}
[data-vibeui-block="kbd-005"] kbd{
display:inline-flex;align-items:center;justify-content:center;
min-width:1.625rem;height:1.625rem;padding:0 0.4375rem;box-sizing:border-box;
background:var(--vibeui-kbd-005-key);
border:1px solid var(--vibeui-kbd-005-border);border-bottom-width:2px;
border-radius:0.4375rem;
font-family:inherit;font-size:0.75rem;font-weight:650;line-height:1;
}
/* Знак ⌘ шире буквы: на Mac клавиша модификатора получает свою ширину. */
[data-vibeui-block="kbd-005"][data-system="mac"] kbd:first-child{min-width:1.875rem}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="kbd-005"] *{animation:none!important;transition:none!important}}
`

const subscribe = () => () => {}
const serverSystem = (): "mac" | "windows" => "windows"

function detect(): "mac" | "windows" {
  if (typeof navigator === "undefined") {
    return "windows"
  }

  return /Mac|iPhone|iPad|iPod/i.test(navigator.userAgent) ? "mac" : "windows"
}

/**
 * Платформозависимое сочетание: ⌘ на macOS, Ctrl на остальных системах.
 * Один файл, ноль зависимостей, собственная палитра.
 */
export function Kbd005({
  platform = "auto",
  action = "Открыть поиск",
  letter = "K",
  className,
  style,
  ...props
}: Kbd005Props) {
  // Систему знает только клиент. useSyncExternalStore отдаёт серверу
  // «windows», а после гидрации — настоящее значение: разметка сервера и
  // клиента совпадают, и состояние не досылается эффектом.
  const detected = useSyncExternalStore(subscribe, detect, serverSystem)

  const system = platform === "auto" ? detected : platform
  const modifier = system === "mac" ? "⌘" : "Ctrl"

  return (
    <>
      <style href="vibeui-kbd-005" precedence="medium">
        {STYLES}
      </style>
      <div
        {...props}
        data-vibeui-block="kbd-005"
        data-system={system}
        className={className}
        style={style as CSSProperties}
      >
        <span data-part="text">
          <span data-part="action">{action}</span>
          <span data-part="system">
            {system === "mac" ? "macOS" : "Windows и Linux"}
          </span>
        </span>
        <span data-part="keys">
          <kbd>{modifier}</kbd>
          <kbd>{letter}</kbd>
        </span>
      </div>
    </>
  )
}