ComponentsSelect

Select

atom

A themed select trigger + option menu — the native picker, restyled to the kit.

Deploy region
Where your app runs.

Recipe CSS

This is the exact CSS your kit ships for Select — token-driven, so it re-themes with every knob. Get it (and the rest) from the configurator's Use kit panel.

/* === Select trigger === */
.select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Same height as inputs (--k-in-h) so a select sitting beside a search
     field stays aligned at EVERY density — adjacent-element rule (#190).
     Was a fixed padding-block:8 that diverged from .in as density grew. */
  min-height: var(--k-in-h-default, 40px);
  padding-block: 0;
  padding-inline: max(var(--k-s-12), calc(var(--k-radius-md) * 0.6));
  /* --k-field-radius (not --k-radius-md) so Plain flattens to a straight
     underline — radius-md here left the bottom hairline curling up at the ends. */
  border-radius: var(--k-field-radius);
  background: var(--k-field-bg);
  border: var(--k-bw, 1px) solid var(--k-field-border-color); border-bottom-color: var(--k-field-underline-color);
  color: var(--k-fg);
  font-size: var(--k-type-small);
  font-family: inherit;
  text-align: left;
  width: 100%;
  cursor: pointer;
}
.select-trigger:hover { border-color: var(--k-state-border, var(--k-fg-faint)); }
/* Invalid state (B1) — a select with a validation error reads like an errored
 * input field: the danger border + a soft danger halo. Mirrors .in.is-error so
 * a select sitting in a form validates with the same language. Toggle with
 * .is-error or aria-invalid="true". */
.select-trigger.is-error,
.select-trigger[aria-invalid="true"] {
  border-color: var(--k-input-error-border);
  box-shadow: 0 0 0 var(--k-ring-w) color-mix(in srgb, var(--k-input-error-border) 22%, transparent);
}

/* Native <select class="select"> as a first-class PREVIEW form control.
 * The configurator chrome has its OWN unscoped `.select` in panel.css
 * (hardcoded 8px radius + --app-* colours). App/preview screens must not
 * borrow that — scope this one to .cockpit-preview and key it to --k-* so a
 * native select matches the .in search field beside it (same radius, surface,
 * border, height) and tracks the box/input radius like every other field.
 * Buttons keep their independent --k-radius-button on purpose (#75). */
.cockpit-preview select.select {
  min-height: var(--k-in-h-default, 40px);
  padding: 0 var(--k-s-28) 0 max(var(--k-s-12), calc(var(--k-radius-md) * 0.6));
  background-color: var(--k-field-bg);
  border: var(--k-bw, 1px) solid var(--k-field-border-color); border-bottom-color: var(--k-field-underline-color);
  border-radius: var(--k-field-radius);
  color: var(--k-fg);
  font-size: var(--k-type-small);
  font-family: var(--k-font-body);
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23888' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  cursor: pointer;
}
.cockpit-preview select.select:hover { border-color: var(--k-state-border, var(--k-fg-faint)); }
.cockpit-preview select.select:focus,
.cockpit-preview select.select:focus-visible {
  outline: none;
  /* Match the .in focus exactly — --k-ring border + --k-ring-halo (28%) shadow.
     Was an UNDEFINED --k-focus-ring token (silently fell back to a 22% halo) so
     the native select's focus read lighter than every sibling field. */
  border-color: var(--k-ring);
  box-shadow: 0 0 0 var(--k-ring-w) var(--k-ring-halo);
}