Button

Exports

Import these components from @mbsw/ui.

Button
buttonVariants

Props

The tables list common props for each component. See the full types for supported prop combinations and inherited HTML and Radix props.

Button

Button props
PropTypeRequirement
generating

Highlight-only visual state. Callers retain aria-busy, disabled and event policy.

booleanOptional
tone'primary' | 'secondary' | 'destructive' | 'highlight'Optional
variant'solid' | 'outline' | 'ghost'Optional
asChildbooleanConditional
childrenNonEmptyButtonChild | ReactElement<unknown, string | JSXElementConstructor<any>>Conditional
iconIconComponentConditional
iconForeground

Secondary direct icon slot only; children styling stays caller-owned.

"primary" | "secondary"Conditional
iconOnlybooleanConditional
leadingIconIconComponentConditional
size'lg' | 'md' | 'sm' | IconOnlyButtonSizeOptional
trailingIconIconComponentConditional
aria-label

Defines a string value that labels the current element.

stringConditional

Type reference

Show full types

Full TypeScript definitions, including prop combinations and inherited props.

import { type ButtonHTMLAttributes, type ElementType, type ReactElement, type ReactNode, type RefAttributes, type SVGProps } from 'react';

export type ButtonVariant = 'solid' | 'outline' | 'ghost';

export type ButtonTone = 'primary' | 'secondary' | 'destructive' | 'highlight';

export type ButtonSize = 'lg' | 'md' | 'sm';

export type IconOnlyButtonSize = ButtonSize | 'xs';

type IconComponent = ElementType<SVGProps<SVGSVGElement>>;

type DataAttributes = {
    [key: `data-${string}`]: boolean | number | string | undefined;
};

type ButtonVariantOptionsBase = {
    className?: string;
    /** Highlight-only presentation; does not change interaction or aria state. */
    generating?: boolean;
    tone?: ButtonTone;
    variant?: ButtonVariant;
};

export type ButtonVariantOptions = (ButtonVariantOptionsBase & {
    iconOnly: true;
    size?: IconOnlyButtonSize;
}) | (ButtonVariantOptionsBase & {
    iconOnly?: false;
    size?: ButtonSize;
});

export declare function buttonVariants(options?: ButtonVariantOptions): string;

type ButtonBaseProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'size'> & DataAttributes & {
    /** Highlight-only visual state. Callers retain aria-busy, disabled and event policy. */
    generating?: boolean;
    tone?: ButtonTone;
    variant?: ButtonVariant;
};

type NonEmptyButtonChild = Exclude<ReactNode, boolean | null | undefined>;

type NativeTextButtonProps = ButtonBaseProps & {
    asChild?: false;
    children: NonEmptyButtonChild;
    icon?: never;
    iconForeground?: never;
    iconOnly?: false;
    leadingIcon?: IconComponent;
    size?: ButtonSize;
    trailingIcon?: IconComponent;
};

type SlottedTextButtonProps = Omit<ButtonBaseProps, 'disabled'> & {
    asChild: true;
    children: ReactElement;
    disabled?: never;
    icon?: never;
    iconForeground?: never;
    iconOnly?: false;
    leadingIcon?: never;
    size?: ButtonSize;
    trailingIcon?: never;
};

type IconOnlyButtonContent = {
    children?: never;
    icon: IconComponent;
    /** Secondary direct icon slot only; children styling stays caller-owned. */
    iconForeground?: 'primary' | 'secondary';
} | {
    children: NonEmptyButtonChild;
    icon?: never;
    iconForeground?: never;
};

type IconOnlyButtonProps = ButtonBaseProps & IconOnlyButtonContent & {
    'aria-label': string;
    asChild?: false;
    iconOnly: true;
    leadingIcon?: never;
    size?: IconOnlyButtonSize;
    trailingIcon?: never;
};

export type ButtonProps = (NativeTextButtonProps & RefAttributes<HTMLButtonElement>) | (SlottedTextButtonProps & RefAttributes<HTMLElement>) | (IconOnlyButtonProps & RefAttributes<HTMLButtonElement>);

type ButtonComponent = {
    (props: ButtonProps): ReactElement | null;
    displayName?: string;
};

export declare const Button: ButtonComponent;