Skip to content

@carrot/design-components-core

Shared component primitives (field wrapper, close button, panel, link, label, divider, sr-only, shortcut) for the Carrot Design System.

Installation

bash
npm install @carrot/design-components-core
css
@import "@carrot/design-components-core";
ts
import {
  CloseBtnSizes, PanelVariants, PanelSizes,
  LinkVariants, LabelSizes, DividerOrientations
} from "@carrot/design-components-core/types";
import type {
  FieldStyleProps, CloseBtnStyleProps, PanelStyleProps,
  LinkStyleProps, LabelStyleProps, DividerStyleProps
} from "@carrot/design-components-core/types";

Contents

Tokens

CSS custom properties defined in @layer kapish.tokens (file: core.css).

Field Wrapper

TokenDefaultDescription
--field-gap--space-1Gap between label, control, and help/error
--field-label-font-size--text-smLabel font size
--field-label-font-weight--font-semiboldLabel font weight
--field-label-color--text-primaryLabel color
--field-help-font-size--text-xsHelp text font size
--field-help-color--text-mutedHelp text color
--field-error-font-size--text-xsError/success message font size
--field-required-color--color-dangerRequired indicator color

Close Button

TokenDefaultDescription
--close-btn-color--text-mutedDefault icon color
--close-btn-hover-color--text-primaryHover icon color
--close-btn-hover-bg--surface-hover-overlayHover background
--close-btn-radius--radius-smBorder radius
--close-btn-size-sm1.25remSmall size
--close-btn-size-md1.75remMedium size (default)
--close-btn-size-lg2remLarge size

Panel

TokenDefaultDescription
--panel-bg--surface-primaryPanel background
--panel-border-color--border-defaultBorder color (outlined)
--panel-border-width1pxBorder width
--panel-radius--radius-lgBorder radius
--panel-padding-sm--space-3Small padding
--panel-padding-md--space-4Medium padding (default)
--panel-padding-lg--space-6Large padding
--panel-padding-xl--space-8Extra-large padding
--panel-raised-shadow--shadow-mdRaised variant shadow
TokenDefaultDescription
--link-muted-color--text-mutedMuted variant color
--link-muted-hover-color--text-primaryMuted variant hover
--link-decorationnoneDefault text-decoration
--link-hover-decorationunderlineHover text-decoration
--link-disabled-opacity0.5Disabled opacity

Label

TokenDefaultDescription
--label-color--text-primaryLabel text color
--label-font-weight--font-semiboldLabel font weight
--label-size-sm--text-xsSmall font size
--label-size-md--text-smMedium font size
--label-size-lg--text-baseLarge font size
--label-disabled-opacity0.5Disabled opacity

Divider

TokenDefaultDescription
--divider-color--border-defaultDivider line color
--divider-width1pxLine width
--divider-stylesolidLine style
--divider-spacing--space-4Margin around divider
--divider-label-color--text-mutedLabel text color
--divider-label-font-size--text-xsLabel font size
--divider-label-gap--space-3Gap around label

Generated Styles

Component classes generated into @layer kapish.components (file: core.g.css).

Field Wrapper

ClassDescription
.fieldVertical flex column -- label -> control -> help/error
.field-labelStyled label text
.field-requiredDanger-colored required indicator (*)
.field-helpMuted help text below control
.field-errorError message (danger color)
.field-successSuccess message (success color)

Modifier: .field[data-horizontal] -- switches to row layout with fixed-width label (8rem min).

Close Button

ClassDescription
.close-btnInline-flex centered button with hover/focus states

Sizes: data-size="sm" · data-size="md" (default) · data-size="lg"

Focus-visible ring is applied via box-shadow.

Panel

ClassDescription
.panelContainer with background, border-radius, and default md padding

Variants: data-variant="outlined" (border) · data-variant="raised" (shadow) · data-variant="ghost" (transparent bg)

Sizes: data-size="sm" · data-size="md" · data-size="lg" · data-size="xl" (controls padding)

Modifier: .panel[data-flush] -- removes all padding.

ClassDescription
.linkAccent-colored link with hover underline and focus-visible ring

Variants: data-variant="muted" (muted color) · data-variant="inherit" (inherits parent color)

Modifiers: .link[data-active] (semibold) · .link[data-disabled] (reduced opacity, no pointer events)

Label

ClassDescription
.labelInline-flex label with default md font size
.label-requiredDanger-colored bold required indicator

Sizes: data-size="sm" · data-size="md" · data-size="lg"

Modifier: .label[data-disabled] -- reduced opacity, default cursor.

Divider

ClassDescription
.dividerHorizontal rule (border-top) with spacing
.divider-labelCentered label text with pseudo-element lines on sides

Orientation: data-orientation="vertical" -- switches to vertical rule (border-left, self-stretching).

Screen Reader Only

ClassDescription
.sr-onlyVisually hidden but accessible to screen readers
.sr-only-focusableHidden until focused (for skip links)

Shortcut

ClassDescription
.shortcut-keyInline-flex keyboard shortcut with border styling
.shortcut-key[data-active]Accent-colored active state
.shortcut-key[data-size="md"]Larger size variant (1.5rem height)
.shortcut-sepSeparator between keys (reduced opacity)

TypeScript Types

ts
CloseBtnSizes          // ["sm", "md", "lg"]
type CloseBtnSize

PanelVariants          // ["default", "outlined", "raised", "ghost"]
type PanelVariant
PanelSizes             // ["sm", "md", "lg", "xl"]
type PanelSize

LinkVariants           // ["accent", "muted", "inherit"]
type LinkVariant

LabelSizes             // ["sm", "md", "lg"]
type LabelSize

DividerOrientations    // ["horizontal", "vertical"]
type DividerOrientation

interface FieldStyleProps { horizontal?: boolean }
interface FieldLabelStyleProps {}
interface FieldRequiredStyleProps {}
interface FieldHelpStyleProps {}
interface FieldErrorStyleProps {}
interface FieldSuccessStyleProps {}
interface CloseBtnStyleProps { size?: CloseBtnSize }
interface PanelStyleProps { variant?: PanelVariant; size?: PanelSize; flush?: boolean }
interface LinkStyleProps { variant?: LinkVariant; active?: boolean; disabled?: boolean }
interface LabelStyleProps { size?: LabelSize; disabled?: boolean }
interface DividerStyleProps { orientation?: DividerOrientation }

Dist Structure

FileDescription
index.cssBarrel -- imports tokens + generated styles
core.cssToken definitions
core.g.cssGenerated component styles
index.js / index.d.tsTypeScript types + runtime constants

Dependencies

Requires tokens from @carrot/design (typography, spacing, colors, surfaces, transitions, elevation).

Build

bash
npm run build

Usage Guide

Import

css
@import "@carrot/design-components-core";
ts
import type {
  FieldStyleProps, CloseBtnStyleProps, PanelStyleProps,
  LinkStyleProps, LabelStyleProps, DividerStyleProps
} from "@carrot/design-components-core/types";

Variants

Field Wrapper

The field wrapper uses data-horizontal for layout switching. No data-variant -- the field is structural only.

Close Button

Close button uses data-size for three size options: sm, md (default), lg.

Panel

Panel uses data-variant for appearance: outlined (border), raised (shadow), ghost (transparent). Use data-size for padding: sm, md, lg, xl. Add data-flush to remove padding entirely.

Link defaults to accent color. Use data-variant="muted" for muted styling or data-variant="inherit" to inherit the parent color. Add data-active for bold weight or data-disabled to disable.

Label

Label defaults to medium size. Use data-size for sm, md, lg. Add data-disabled to dim. Use .label-required for the required indicator.

Divider

Divider is horizontal by default. Use data-orientation="vertical" for a vertical rule. Nest a .divider-label element for a labelled divider with lines on either side.

Screen Reader Only

Use .sr-only to visually hide content while keeping it accessible. Use .sr-only-focusable for skip links that appear on focus.

Shortcut

Use .shortcut-key for keyboard shortcut indicators. Add data-active for the active/pressed state. Use data-size="md" for a larger variant. Use .shortcut-sep between keys.

Examples

Basic vertical field

html
<!-- Standard vertical field with label, input, and help text -->
<div class="field">
  <label class="field-label">
    Email address
    <span class="field-required">*</span>
  </label>
  <input type="email" class="input" placeholder="you@example.com" />
  <span class="field-help">We'll never share your email.</span>
</div>

Field with error state

html
<!-- Field displaying a validation error -->
<div class="field">
  <label class="field-label">Username</label>
  <input type="text" class="input" data-state="error" value="x" />
  <span class="field-error">Username must be at least 3 characters.</span>
</div>

Field with success state

html
<!-- Field displaying a success confirmation -->
<div class="field">
  <label class="field-label">Password</label>
  <input type="password" class="input" data-state="success" />
  <span class="field-success">Password meets requirements.</span>
</div>

Horizontal layout

html
<!-- Horizontal field: label sits to the left of the control -->
<div class="field" data-horizontal>
  <label class="field-label">Display name</label>
  <input type="text" class="input" />
</div>

Close button sizes

html
<!-- Small close button (e.g. inside a badge) -->
<button class="close-btn" data-size="sm" aria-label="Remove">
  <svg><!-- x icon --></svg>
</button>

<!-- Default medium close button (e.g. inside a toast) -->
<button class="close-btn" aria-label="Dismiss">
  <svg><!-- x icon --></svg>
</button>

<!-- Large close button (e.g. inside a modal header) -->
<button class="close-btn" data-size="lg" aria-label="Close dialog">
  <svg><!-- x icon --></svg>
</button>

Panel variants

html
<!-- Default panel -->
<div class="panel">Default panel content</div>

<!-- Outlined panel -->
<div class="panel" data-variant="outlined">Outlined with border</div>

<!-- Raised panel with large padding -->
<div class="panel" data-variant="raised" data-size="lg">Raised with shadow</div>

<!-- Ghost panel (transparent background) -->
<div class="panel" data-variant="ghost">Ghost panel</div>

<!-- Flush panel (no padding) -->
<div class="panel" data-variant="outlined" data-flush>No padding</div>
html
<!-- Default accent link -->
<a class="link" href="/about">About us</a>

<!-- Muted link -->
<a class="link" data-variant="muted" href="/terms">Terms</a>

<!-- Inherit-color link -->
<a class="link" data-variant="inherit" href="/help">Help</a>

<!-- Active link -->
<a class="link" data-active href="/dashboard">Dashboard</a>

<!-- Disabled link -->
<a class="link" data-disabled>Unavailable</a>

Label

html
<!-- Standard label -->
<label class="label">First name</label>

<!-- Label with required indicator -->
<label class="label">
  Email
  <span class="label-required">*</span>
</label>

<!-- Small label -->
<label class="label" data-size="sm">Optional hint</label>

<!-- Disabled label -->
<label class="label" data-disabled>Locked field</label>

Divider

html
<!-- Horizontal divider -->
<hr class="divider" />

<!-- Vertical divider (e.g. in a flex row) -->
<div class="divider" data-orientation="vertical"></div>

<!-- Labelled divider -->
<div class="divider">
  <span class="divider-label">Or continue with</span>
</div>

Screen reader only

html
<!-- Visually hidden label for accessibility -->
<span class="sr-only">Navigation menu</span>

<!-- Skip-to-content link (visible on focus) -->
<a class="sr-only-focusable" href="#main">Skip to main content</a>

Shortcut keys

html
<!-- Single key -->
<kbd class="shortcut-key">K</kbd>

<!-- Key combo with separator -->
<kbd class="shortcut-key">Ctrl</kbd>
<span class="shortcut-sep">+</span>
<kbd class="shortcut-key">K</kbd>

<!-- Active state -->
<kbd class="shortcut-key" data-active>Enter</kbd>

<!-- Medium size -->
<kbd class="shortcut-key" data-size="md">Space</kbd>

With Vue

Use @carrot/design-vue-core for <SbField>, <SbFieldLabel>, <SbFieldHelp>, <SbFieldError>, <SbCloseBtn>, <SbPanel>, <SbLink>, <SbLabel>, <SbDivider>, and <SbShortcut> components that accept the typed props.

Carrot