sdxc

Type to search, or start from one of these:

Button

An interactive control for a single, immediate action — submitting a form, triggering a command, opening a dialog.

sk_live_7Qm2X9cVb0
View code
const COPY_LABELS = {
	idle: "Copy key",
	copied: "Copied",
	refused: "Clipboard refused",
};

let copyState: keyof typeof COPY_LABELS = "idle";

<div mix={[vstack({ gap: 5, align: "start" })]}>
	<div mix={[hstack({ gap: 3, align: "center" }), flexWrap()]}>
		<Button type="submit">Save changes</Button>
		<Button type="button" variant="outline" color="neutral">
			Discard
		</Button>
		<Button type="button" variant="ghost" color="danger">
			<Trash2Icon size={16} aria-hidden="true" />
			Delete project
		</Button>
		<Button type="button" isPending>
			Publishing
		</Button>
		<Button type="button" disabled>
			Merge blocked
		</Button>
	</div>

	<div mix={[hstack({ gap: 3, align: "center" }), flexWrap()]}>
		<Button type="button" size="lg">
			Start free trial
		</Button>
		<Button type="button" size="md" variant="outline">
			Book a demo
		</Button>
		<Button type="button" size="sm" variant="ghost" color="neutral">
			Learn more
		</Button>
		<Button type="button" size="sm" aria-label="Invite a teammate">
			<PlusIcon size={16} />
		</Button>
	</div>

	<div mix={[hstack({ gap: 3, align: "center" }), flexWrap()]}>
		<code
			id="preview-button-token"
			mix={[font("mono"), text("sm"), p(2, 3), rounded("md"), bg("neutral.tint")]}
		>
			sk_live_7Qm2X9cVb0
		</code>
		<Button
			type="button"
			variant="outline"
			color="neutral"
			size="sm"
			commandfor="preview-button-token"
			command={COPY_COMMAND}
			mix={[
				copyToClipboard(),
				on<HTMLButtonElement, "ui:copy">("ui:copy", (event) => {
					copyState = event.success ? "copied" : "refused";
					void handle.update();
				}),
			]}
		>
			{copyState === "copied" ? (
				<CheckIcon size={16} aria-hidden="true" />
			) : (
				<CopyIcon size={16} aria-hidden="true" />
			)}
			{COPY_LABELS[copyState]}
		</Button>
	</div>
</div>

Installation

An ordinary dependency: install it, import the theme once, and import the component where it is used.

npm add @sdxc/ui
import "@sdxc/ui/theme.css";

Usage

import { Button } from "@sdxc/ui";

Prop types for Button.

Props

Read from the component's own types, so every prop, every default and every allowed value is listed.

PropTypeDescription
color?"brand" | "neutral" | "success" | "warning" | "danger"Semantic color role. Defaults to DEFAULT_COLOR.
variant?"solid" | "outline" | "ghost"Visual weight. Defaults to DEFAULT_VARIANT.
size?"sm" | "md" | "lg"Size variant. Defaults to DEFAULT_SIZE.
isPending?booleanMarks the button busy: merges into the native disabled attribute and swaps the visible content for a spinner glyph while holding the rendered footprint, so a page mid-request keeps its layout.
parts?PartsPropsPer-part styling for the pending state's internal elements.

Also accepts everything in TagProps<"button">.

Types

NameValuesWhat it decides
Color"brand" | "neutral" | "success" | "warning" | "danger"Semantic color role, each mapped to its matching --ui-* variables.
Variant"solid" | "outline" | "ghost"Visual weight the button renders with: a solid fill with an on-solid foreground, a transparent fill with a strong colored border, or a fully transparent fill with just a colored label.
Size"sm" | "md" | "lg"Size variant controlling the button's padding and font size.