Control styles
Semantic control palettes express emphasis and selection while sharing Bosun’s surfaces, typography and interaction states.
On this page
--raised-enabled-…--raised-hover-…--raised-pressed-…--raised-activated-…--raised-focused-…--raised-disabled-…These are token swatches, not disabled or focusable controls. Try real controls on the Interaction states page.
Code
import { useState, type CSSProperties, type Dispatch, type SetStateAction, type ReactElement } from "react";
import { Select } from "@bosunkit/components/select";
import { Stack } from "@bosunkit/components/stack";
import { Text } from "@bosunkit/components/text";
import { PresentationScope } from "@bosunkit/provider";
import { THEMES, type Theme } from "@bosunkit/tokens/theme";
import "./example.css";
export const description: string =
"Choose a control style and theme to inspect its token pairs in every interaction state.";
const STYLES: readonly string[] = [
"normal",
"flat",
"raised",
"indent",
"selected",
"amplified",
"thumb",
"notification",
"integration-normal",
"integration-flat",
"integration-selected",
"integration-indent",
];
const STATES: readonly string[] = ["enabled", "hover", "pressed", "activated", "focused", "disabled"];
export default function Example(): ReactElement {
const [family, setFamily]: [string, Dispatch<SetStateAction<string>>] = useState<string>("raised");
const [theme, setTheme]: [Theme | "inherit", Dispatch<SetStateAction<Theme | "inherit">>] = useState<
Theme | "inherit"
>("inherit");
const foreground: string = family.endsWith("selected")
? "bk-control-selected-text"
: family === "notification"
? "bk-control-notification-text"
: family.startsWith("integration-")
? `integration-on-${family.slice(12)}-active-color`
: `on-${family}-active-color`;
return (
<Stack space="lg">
<div className="foundation-control-options">
<Select.Root value={family} onValueChange={(next: string | null): void => { (setFamily)(next ?? ""); }}>
<Select.Trigger aria-label="Control style">
<Select.Value />
</Select.Trigger>
<Select.Portal><Select.Positioner alignItemWithTrigger={true} ><Select.Popup ><Select.List>
{STYLES.map((name: string): ReactElement => (
<Select.Item key={name} value={name}>
{name}
</Select.Item>
))}
</Select.List></Select.Popup></Select.Positioner></Select.Portal>
</Select.Root>
<Select.Root
value={theme}
onValueChange={(next: string | null): void => { ((value: string): void => {
if (value === "inherit" || THEMES.includes(value as Theme)) setTheme(value as Theme | "inherit");
})(next ?? ""); }}
>
<Select.Trigger aria-label="Specimen theme">
<Select.Value />
</Select.Trigger>
<Select.Portal><Select.Positioner alignItemWithTrigger={true} ><Select.Popup ><Select.List>
<Select.Item value="inherit">Page theme</Select.Item>
{THEMES.map((name: Theme): ReactElement => (
<Select.Item key={name} value={name}>
{name}
</Select.Item>
))}
</Select.List></Select.Popup></Select.Positioner></Select.Portal>
</Select.Root>
</div>
<PresentationScope theme={theme === "inherit" ? undefined : theme}>
<div className="foundation-control-grid" aria-label="Control token specimens">
{STATES.map((state: string): ReactElement => {
const ink: string = state === "disabled" ? "text-dim" : foreground;
const style: CSSProperties = {
background: `var(--${family}-${state}-background-color)`,
borderColor: `var(--${family}-${state}-border-color)`,
color: `var(--${ink})`,
outline: state === "focused" ? "var(--bk-focus-width) solid var(--bk-focus-ring)" : undefined,
};
return (
<figure key={state} className="foundation-control-cell">
<div className="foundation-control-swatch" style={style}>
Aa
</div>
<figcaption>
{state}
<code>
--{family}-{state}-…
</code>
</figcaption>
</figure>
);
})}
</div>
</PresentationScope>
<Text variant="caption" color="text-dim">
These are token swatches, not disabled or focusable controls. Try real controls on the Interaction states page.
</Text>
</Stack>
);
}
Style and state are separate
A style identifies the control’s visual role. A state describes what is happening to that control. A selected option can also be hovered, pressed, focused or disabled. Its selection remains visible through each state. OpenBridge styles and states provides the vocabulary; Bosun maps it to the elevation, color, spacing and typography foundations.
| Style | Use | Bosun treatment |
|---|---|---|
normal | Ordinary actions | Neutral surface, readable label and a hairline. |
flat | Quiet toolbar actions and navigation | Transparent at rest; interaction adds a surface or outline. |
raised | A control that needs stronger emphasis | Surface and outline contrast, without a resting shadow. |
indent | Recessed input or control well | Inset surface; the label remains separate from placeholder text. |
selected | A persistent choice | Accent treatment plus a check, indicator or explicit selected semantics. |
amplified | Strong neutral emphasis | Brighter text and stronger outline, without an alert hue. |
thumb | A slider or switch grip | Neutral grip with a distinct focus and disabled treatment. |
notification | Information outside alert management | Notification palette and readable foreground, never a priority color. |
integration-* | Navigation between systems or workspaces | The matching normal, flat, selected or inset palette; no competing brand color. |
These are palette roles, not extra variants on every component. Use the component’s documented API; do not restyle a Button into an unsupported variant at the call site. The Button, Navigation list and Brilliance menu pages show their supported combinations.
Token anatomy
Background and outline tokens use --<style>-<state>-background-color and --<style>-<state>-border-color.
The states are enabled, hover, pressed, activated, focused and disabled.
activated names a persistent activation in the OpenBridge vocabulary; pressed lasts only for the input gesture.
Integration controls add integration- before the role.
Text and icons are a separate layer. --on-<style>-active-color, -neutral-color and -disabled-color describe
the foreground. For labels on strong fills, use the dedicated text pair:
| Foreground | Background | Purpose |
|---|---|---|
--bk-control-selected-text | --selected-enabled-background-color | Text on a selected fill. |
--bk-control-notification-text | --notification-enabled-background-color | Text on a notification fill. |
--bk-action-text | Page or neutral control surface | Accent-colored text using the theme’s readable accent step. |
--bk-focus-ring | The control’s surrounding surface | Keyboard focus, drawn independently of selection. |
The selected and notification text pairs are checked at the text contrast floor in all four themes. Icon colors and fill colors are not automatically safe for small text. Check the actual background, especially when a fill is transparent or mixed with another surface.
| Token | Night | Dusk | Day | Bright |
|---|---|---|---|---|
--raised-enabled-background-colorRaised control | #1A140B | #1A1B20 | #F6F7F9 | #E2E5E9 |
--raised-pressed-border-colorPressed outline | #8F6130 | #8B8F98 | #5B6068 | #4B5058 |
--selected-enabled-background-colorSelected fill | #48341F | #14B8A6 | #0D9488 | #0D9488 |
--bk-control-selected-textText on selected fill | #FFC878 | #0B0C0F | #0B0C0F | #0B0C0F |
--notification-enabled-background-colorNotification fill | #286550 | #84B3EF | #2D548B | #1D3C67 |
--bk-control-notification-textText on notification fill | #FFCA7A | #0B0C0F | #FFFFFF | #FFFFFF |
--bk-focus-ringKeyboard focus | #FFC878 | #14B8A6 | #0D645E | #0D645E |
Applying the palette
Bosun buttons use --bk-control-* roles for their raised surface, outline and foreground. Inputs and select
triggers use --bk-field-*. Primary actions and selected navigation labels use --bk-action-text; their actual
mixed backgrounds are included in contrast checks. Focus uses --bk-focus-ring, --bk-focus-width and
--bk-focus-offset, independently of an invalid border or selected indicator. A chosen segment or row takes
--bk-selected-background and is marked by --bk-selected-indicator; an invalid field's dashed border is
--bk-field-invalid-border, the text color. These house roles follow the amber Night interface palette, in which
red marks only the alarm; instruments retain their own presentation roles.
background: var(--normal-pressed-background-color);background: var(--alert-alarm-color);Use the shared text roles for labels, the spacing scale for padding, and the target rules for touch. A palette does not change a target’s size, imply a shadow, or determine whether an action is allowed. The component owns those behaviors.
Coverage
The kit defines all six background and border states for the roles above. Integration foregrounds and surfaces
alias the same foundations, and nested PresentationScope themes resolve the aliases locally.
The source vocabulary is pinned to OpenBridge 2.0.0-next.128; this is a palette contract for Bosunkit’s controls,
not a claim that every upstream web component is available. Automation, augmented-reality overlays and additional
alert-control families need their own semantic review before adoption.
Related
- Interaction states: behavior, state precedence and working controls.
- Themes: palettes, scopes, automatic selection and brightness.
- Elevation: surface emphasis and shadows.
- Color: meaning and contrast limits.