๐ŸŸข Kbd

Work in progress - this component is not yet ready for use.

Basic

NKbd is a component for indicating input that is typically entered via keyboard.

You can use label prop or default slot to set the value kbd.

โŒ˜KFnCtrl
<template>
  <div flex="~ wrap" gap-4>
    <NKbd label="โŒ˜" />

    <NKbd label="K" />

    <NKbd label="Fn" />

    <NKbd label="Ctrl" />
  </div>
</template>

Variants

kbd="{variant}" - change the variant of the kbd.

VariantDescription
solidThe default variant.
outlineThe outline variant.
~The unstyle or base variant
EnterEnterEnter
<template>
  <div flex="~ wrap" gap-4>
    <NKbd kbd="solid" label="Enter" />

    <NKbd kbd="outline" label="Enter" />

    <NKbd kbd="~" label="Enter" />
  </div>
</template>

Color

kbd="{variant}-{color}" - change the color of the kbd.

You can use any color provided by the Tailwind CSS color palette, the default is primary. You can also add your own colors to the palette through the Configuration section.
โŒ˜โŒ˜โŒ˜โŒ˜
<template>
<div flex="~ wrap" gap-4>
  <NKbd kbd="solid-lime" label="โŒ˜" />

  <NKbd kbd="solid-rose" label="โŒ˜" />

  <NKbd kbd="outline-pink" label="โŒ˜" />

  <NKbd kbd="outline-orange" label="โŒ˜" />
</div>
</template>

Sizes

NKbd can be sized using the size prop.

๐Ÿš€ You can freely adjust the size of the kbd using any size imaginable. No limits exist, and you can use breakpoints such as sm:sm, xs:lg to change size based on screen size or states such as hover:lg, focus:3xl to change size based on input state and more.

The padding and font-size of the kbd scale depends on the size. If you want to change the font-size and padding simultaneously, you can always customize it using utility classes.
โŒ˜โŒ˜โŒ˜โŒ˜โŒ˜
<template>
  <div flex="~ wrap" gap-4>
    <NKbd label="โŒ˜" size="11px" />
    <NKbd label="โŒ˜" size="12px" />
    <NKbd label="โŒ˜" size="13px" />
    <NKbd label="โŒ˜" size="sm" />
    <NKbd label="โŒ˜" size="xl" />
  </div>
</template>

Usage with Other Components

NKbd can be used with other components to create more complex elements e.g:

  • can be used with NButton to create a button that is triggered by a keyboard shortcut.
  • can be used with NInput to create an input that is triggered by a keyboard shortcut.
size prop is automatically inherited from the parent component when used with other components.
โŒ˜ K
<template>
  <div flex="~ wrap" gap-4>
    <NButton
      label="Search"
      btn="soft-gray"
      leading="i-heroicons-magnifying-glass"
      class="font-normal"
    >
      <template #trailing>
        <span class="ml-3 inline-flex items-center space-x-0.5" size="md">
          <NKbd label="Cmd" />
          <NKbd label="K" />
        </span>
      </template>
    </NButton>

    <NButton
      label="Search"
      btn="soft"
      leading="i-heroicons-magnifying-glass"
      class="font-normal"
    >
      <template #trailing>
        <span class="ml-3 inline-flex items-center space-x-0.5" size="md">
          <NKbd kbd="solid-primary" label="Cmd" />
          <NKbd kbd="solid-primary" label="K" />
        </span>
      </template>
    </NButton>

    <NInput placeholder="Search" class="pr-13">
      <template #trailing>
        <NKbd label="โŒ˜ K" kbd="outline" />
      </template>
    </NInput>
  </div>
</template>

Slots

Default

#default - set the kbd value.

Props

export interface NKbdProps {
  /**
   * Allows you to add `UnaUI` kbd preset properties,
   * Think of it as a shortcut for adding options or variants to the preset if available.
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/kbd.ts
   * @example
   * kbd="solid-error"
   */
  kbd?: string
  /**
   * Add a label to the kbd.
   *
   * @example
   * label="Ctrl"
   */
  label?: string

  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/kbd.ts
   */
  una?: {
    kbd?: string
  }
}

Presets

type KbdPrefix = 'kbd'

export const staticKbd: Record<`${KbdPrefix}-${string}` | KbdPrefix, string> = {
  // config
  'kbd-default-variant': 'kbd-solid-gray',

  // base
  'kbd': 'inline-flex text-nowrap items-center h-1.8181818181818181em min-w-1.8181818181818181em font-sans justify-center rounded px-0.5454545454545454em py-0.18181818181818182em text-0.6875em font-normal',
}

export const dynamicKbd: [RegExp, (params: RegExpExecArray) => string][] = [
  // modifiers
  [/^kbd-ring(-(\S+))?$/, ([, , c = 'gray']) => `ring ring-inset ring-${c}-200 dark:ring-${c}-700`],

  // variants
  [/^kbd-solid(-(\S+))?$/, ([, , c = 'gray']) => `kbd-ring-${c} bg-${c}-50 text-${c}-500 dark:bg-${c}-950 dark:text-${c}-400`],
  [/^kbd-outline(-(\S+))?$/, ([, , c = 'gray']) => `kbd-ring-${c} bg-transparent text-${c}-500 dark:text-${c}-400`],
]

export const kbd = [
  ...dynamicKbd,
  staticKbd,
]

Component

<script setup lang="ts">
import { computed } from 'vue'
import type { NKbdProps } from '../../types'

const props = defineProps<NKbdProps>()

const kbdVariants = ['solid', 'outline'] as const
const hasVariant = computed(() => kbdVariants.some(kbdVariants => props.kbd?.includes(kbdVariants)))
const isBaseVariant = computed(() => props.kbd?.includes('~'))
</script>

<template>
  <kbd
    class="kbd"
    :kbd="kbd"
    :class="[
      { 'kbd-default-variant': !hasVariant && !isBaseVariant },
      una?.kbd,
    ]"
  >
    <slot>
      {{ label }}
    </slot>
  </kbd>
</template>