diff --git a/src/plugins/components/index.ts b/src/plugins/components/index.ts
index 3254ac3..af462f3 100644
--- a/src/plugins/components/index.ts
+++ b/src/plugins/components/index.ts
@@ -24,6 +24,7 @@ import inputFileRegular from './input-file-regular'
import inputFile from './input-file'
import input from './input'
import inputNumber from './input-number'
+import kbd from './kbd'
import label from './label'
import link from './link'
import list from './list'
@@ -80,6 +81,7 @@ const components = [
inputFile,
input,
inputNumber,
+ kbd,
label,
link,
list,
diff --git a/src/plugins/components/kbd/index.ts b/src/plugins/components/kbd/index.ts
new file mode 100644
index 0000000..ab189cd
--- /dev/null
+++ b/src/plugins/components/kbd/index.ts
@@ -0,0 +1,159 @@
+import plugin from 'tailwindcss/plugin'
+import { defu } from 'defu'
+import { type PluginOption, defaultPluginOptions } from '../../options'
+import { type KbdPluginConfig, defaultConfig, key } from './kbd.config'
+
+export default plugin.withOptions(
+ function (options: PluginOption) {
+ let { prefix } = defu(options, defaultPluginOptions)
+
+ if (prefix) {
+ prefix = `${prefix}-`
+ }
+
+ return function ({ addComponents, theme }) {
+ const config = theme(`shurikenUi.${key}`) satisfies KbdPluginConfig
+
+ addComponents({
+ [`.${prefix}kbd`]: {
+ [`@apply inline-flex items-center justify-center`]: {},
+ //Font
+ [`@apply font-${config.font.family} leading-none text-${config.font.color.light} dark:text-${config.font.color.dark}`]:
+ {},
+ //Icon:outer
+ [`.${prefix}kbd-icon-outer`]: {
+ [`@apply inline-flex items-center justify-center`]: {},
+ },
+ //Icon:inner
+ [`.${prefix}kbd-icon`]: {
+ [`@apply shrink-0`]: {},
+ },
+ //Rounded:sm
+ [`&.${prefix}kbd-rounded-sm`]: {
+ [`@apply ${config.rounded.sm}`]: {},
+ },
+ //Rounded:md
+ [`&.${prefix}kbd-rounded-md`]: {
+ [`@apply ${config.rounded.md}`]: {},
+ },
+ //Rounded:lg
+ [`&.${prefix}kbd-rounded-lg`]: {
+ [`@apply ${config.rounded.lg}`]: {},
+ },
+ //Rounded:full
+ [`&.${prefix}kbd-rounded-full`]: {
+ [`@apply ${config.rounded.full}`]: {},
+ },
+ //Size:xs
+ [`&.${prefix}kbd-xs`]: {
+ [`@apply font-medium`]: {},
+ //Size
+ [`@apply min-h-[${config.size.xs.size}] min-w-[${config.size.xs.size}]`]:
+ {},
+ //Padding
+ [`@apply px-${config.size.xs.padding.x} py-${config.size.xs.padding.y}`]:
+ {},
+ //Font
+ [`@apply leading-${config.size.xs.font.lead} text-${config.size.xs.font.size}`]:
+ {},
+ //Icon:outer
+ [`.${prefix}kbd-icon-outer`]: {
+ [`@apply w-${config.size.xs.icon.outer.size} h-${config.size.xs.icon.outer.size}`]:
+ {},
+ },
+ //Icon:inner
+ [`.${prefix}kbd-icon-inner`]: {
+ [`@apply w-${config.size.xs.icon.inner.size} h-${config.size.xs.icon.inner.size}`]:
+ {},
+ },
+ },
+ //Size:sm
+ [`&.${prefix}kbd-sm`]: {
+ //Size
+ [`@apply min-h-[${config.size.sm.size}] min-w-[${config.size.sm.size}]`]:
+ {},
+ //Padding
+ [`@apply px-${config.size.sm.padding.x} py-${config.size.sm.padding.y}`]:
+ {},
+ //Font
+ [`@apply leading-${config.size.sm.font.lead} text-${config.size.sm.font.size}`]:
+ {},
+ //Icon:outer
+ [`.${prefix}kbd-icon-outer`]: {
+ [`@apply w-${config.size.sm.icon.outer.size} h-${config.size.sm.icon.outer.size}`]:
+ {},
+ },
+ //Icon:inner
+ [`.${prefix}kbd-icon-inner`]: {
+ [`@apply w-${config.size.sm.icon.inner.size} h-${config.size.sm.icon.inner.size}`]:
+ {},
+ },
+ },
+ //Size:md
+ [`&.${prefix}kbd-md`]: {
+ //Size
+ [`@apply min-h-[${config.size.md.size}] min-w-[${config.size.md.size}]`]:
+ {},
+ //Padding
+ [`@apply px-${config.size.md.padding.x} py-${config.size.md.padding.y}`]:
+ {},
+ //Font
+ [`@apply leading-${config.size.md.font.lead} text-${config.size.md.font.size}`]:
+ {},
+ //Icon:outer
+ [`.${prefix}kbd-icon-outer`]: {
+ [`@apply w-${config.size.md.icon.outer.size} h-${config.size.md.icon.outer.size}`]:
+ {},
+ },
+ //Icon:inner
+ [`.${prefix}kbd-icon-inner`]: {
+ [`@apply w-${config.size.md.icon.inner.size} h-${config.size.md.icon.inner.size}`]:
+ {},
+ },
+ },
+ //Size:lg
+ [`&.${prefix}kbd-lg`]: {
+ //Size
+ [`@apply min-h-[${config.size.lg.size}] min-w-[${config.size.lg.size}]`]:
+ {},
+ //Padding
+ [`@apply px-${config.size.lg.padding.x} py-${config.size.lg.padding.y}`]:
+ {},
+ //Font
+ [`@apply leading-${config.size.lg.font.lead} text-${config.size.lg.font.size}`]:
+ {},
+ //Icon:outer
+ [`.${prefix}kbd-icon-outer`]: {
+ [`@apply w-${config.size.lg.icon.outer.size} h-${config.size.lg.icon.outer.size}`]:
+ {},
+ },
+ //Icon:inner
+ [`.${prefix}kbd-icon-inner`]: {
+ [`@apply w-${config.size.lg.icon.inner.size} h-${config.size.lg.icon.inner.size}`]:
+ {},
+ },
+ },
+ //Color:default
+ [`&.${prefix}kbd-default`]: {
+ [`@apply bg-white dark:bg-muted-800 border border-b-2 border-muted-500/20 dark:border-muted-300/20`]:
+ {},
+ },
+ //Color:muted
+ [`&.${prefix}kbd-muted`]: {
+ [`@apply bg-muted-50 dark:bg-muted-800 border border-b-2 border-muted-600/20 dark:border-muted-300/20`]:
+ {},
+ },
+ },
+ })
+ }
+ },
+ function () {
+ return {
+ theme: {
+ shurikenUi: {
+ [key]: defaultConfig,
+ },
+ },
+ }
+ },
+)
diff --git a/src/plugins/components/kbd/kbd.component.ts b/src/plugins/components/kbd/kbd.component.ts
new file mode 100644
index 0000000..f3ffc51
--- /dev/null
+++ b/src/plugins/components/kbd/kbd.component.ts
@@ -0,0 +1,34 @@
+import { html } from 'lit'
+import { spread } from '@open-wc/lit-helpers'
+
+import type { KbdAttrs } from './kbd.types'
+import * as variants from './kbd.variants'
+
+/**
+ * Primary UI component for user interaction
+ */
+export const Kbd = ({
+ rounded = 'md',
+ size = 'md',
+ color = 'default',
+ classes,
+ children,
+ ...attrs
+}: KbdAttrs) => {
+ return html`
+
+ ${children}
+
+ `
+}
diff --git a/src/plugins/components/kbd/kbd.config.ts b/src/plugins/components/kbd/kbd.config.ts
new file mode 100644
index 0000000..37369cb
--- /dev/null
+++ b/src/plugins/components/kbd/kbd.config.ts
@@ -0,0 +1,122 @@
+export const key = 'kbd' as const
+
+export const defaultConfig = {
+ font: {
+ family: 'mono',
+ color: {
+ light: 'muted-700',
+ dark: 'muted-200',
+ },
+ },
+ rounded: {
+ sm: 'rounded-sm',
+ md: 'rounded-md',
+ lg: 'rounded-lg',
+ full: 'rounded-full',
+ },
+ size: {
+ xs: {
+ font: {
+ size: 'xs',
+ lead: '4',
+ },
+ padding: {
+ x: '1',
+ y: '0.5',
+ },
+ size: '1.2em',
+ icon: {
+ outer: {
+ size: '4',
+ },
+ inner: {
+ size: '3.5',
+ },
+ },
+ },
+ sm: {
+ font: {
+ size: 'sm',
+ lead: '5',
+ },
+ padding: {
+ x: '1',
+ y: '0.5',
+ },
+ size: '1.6em',
+ icon: {
+ outer: {
+ size: '5',
+ },
+ inner: {
+ size: '3.5',
+ },
+ },
+ },
+ md: {
+ font: {
+ size: 'base',
+ lead: '6',
+ },
+ padding: {
+ x: '2',
+ y: '1',
+ },
+ size: '2.2em',
+ icon: {
+ outer: {
+ size: '5',
+ },
+ inner: {
+ size: '4',
+ },
+ },
+ },
+ lg: {
+ font: {
+ size: 'lg',
+ lead: '7',
+ },
+ padding: {
+ x: '4',
+ y: '1',
+ },
+ size: '2.5em',
+ icon: {
+ outer: {
+ size: '6',
+ },
+ inner: {
+ size: '5',
+ },
+ },
+ },
+ },
+ color: {
+ default: {
+ background: {
+ light: 'white',
+ dark: 'muted-800',
+ },
+ border: {
+ light: 'muted-500/20',
+ dark: 'muted-300/20',
+ },
+ },
+ muted: {
+ background: {
+ light: 'muted-50',
+ dark: 'muted-800',
+ },
+ border: {
+ light: 'muted-600/20',
+ dark: 'muted-300/20',
+ },
+ },
+ },
+}
+
+export type KbdConfig = typeof defaultConfig
+export interface KbdPluginConfig {
+ [key]: KbdConfig
+}
diff --git a/src/plugins/components/kbd/kbd.doc.mdx b/src/plugins/components/kbd/kbd.doc.mdx
new file mode 100644
index 0000000..dfe0bef
--- /dev/null
+++ b/src/plugins/components/kbd/kbd.doc.mdx
@@ -0,0 +1,93 @@
+import { Meta, Primary, Controls, Story } from '@storybook/blocks'
+import * as KbdStories from './kbd.stories'
+import { defaultConfig } from './kbd.config'
+
+
+
+# Kbd
+Sometimes you need to display a keyboard key (such as when displaying keyboard shortcuts) in your UI. The Kbd component is used to indicate input that is typically entered via the keyboard.
+
+
+
+### Color: default
+
+Kbd elements can have different sizes and colors. Below is an eample of available sizes and with the default color.
+
+
+ {JSON.stringify(defaultConfig, null, 2)} ++