actions/DSButton

DSButton

actions
since v1.0

Universal button component with 5 visual variants, 3 sizes, icon support, loading and disabled states. Uses spring animations for micro-interactions.

iOS 17+macOS 14+watchOS 10+visionOS 1+

Purpose

DSButton is the primary action component in the system. Use it in forms, dialogs, and any situation that requires an explicit user action.

Variants

Primary

.primary

Main action on the screen. Use only one per visible context.

Secondary

.secondary

Secondary action complementing the primary.

Ghost

.ghost

Tertiary or low-priority action. Transparent background.

Destructive

.destructive

Irreversible actions such as deleting or cancelling a subscription.

Success

.success

Confirmation of a successful action or approval.

States

default

Resting state.

hover

Slight scale up (1.015×) with a subtly different color.

pressed

Scale down to 0.96× via spring animation.

loading

Replaces the label with DSSpinner. Action is disabled.

disabled

45% opacity. All events are blocked.

Props

PropTypeDefaultDescription
titlereqStringButton label text.
variantDSButtonVariant.primaryVisual style.
sizeDSButtonSize.mdSize (.sm, .md, .lg).
iconString?nilSF Symbol to display alongside the text.
iconPositionHorizontalAlignment.leadingIcon position (.leading or .trailing).
isLoadingBoolfalseShows spinner and disables action.
isDisabledBoolfalseDisables the button.
actionreq(() -> Void)Closure executed on tap.

Examples

Basic usage

Primary button with a simple action.

swift
DSButton("Save", variant: .primary) {
    viewModel.save()
}

With icon and loading state

Button that shows a spinner while saving.

swift
DSButton(
    "Submit",
    variant: .primary,
    icon: "paperplane.fill",
    isLoading: viewModel.isSaving
) {
    viewModel.submit()
}

Action group

Combination of primary, secondary and ghost.

swift
HStack(spacing: DSSpacing.sm) {
    DSButton("Confirm", variant: .primary, action: confirm)
    DSButton("Cancel", variant: .ghost, action: cancel)
}

Destructive with confirmation

Always pair with a confirmation dialog.

swift
DSButton("Delete account", variant: .destructive) {
    showConfirmationAlert = true
}

Usage Guidelines

  • Use at most 1 primary button per visual section.
  • Never disable buttons without explaining the reason to the user via hint text.
  • On mobile, ensure a minimum height of 44pt for accessibility.
  • Prefer the .ghost variant for navigation actions or inline links.

When to Use

✓ Use DSButton for:

  • Primary actions in forms, dialogs, and screens (Save, Submit, Confirm)
  • Call-to-action buttons in marketing sections
  • Destructive actions with confirmation (Delete, Remove)
  • Success confirmations (Complete, Approve)

✗ Avoid using for:

  • Navigation between screens (use NavigationLink or DSLink)
  • Icon-only actions in toolbars (use DSIconButton)
  • Inline text actions (use DSLink)
  • More than 3 buttons in a row (consider DSMenuButton or DSBottomSheet)

Consider instead:

DSLink

For inline text links or secondary navigation

DSIconButton

For icon-only actions in compact spaces

DSMenuButton

For grouped actions or overflow menus

Accessibility

VoiceOver

Announces label and state (e.g., 'Save, button' or 'Save, loading, button'). Disabled state is announced automatically.

Keyboard

  • Space or Return to activate
  • Tab to focus in forms
  • Command+Return for primary actions

Dynamic Type

✓ Supported

Contrast

Colors follow design best practices for readability in both light and dark modes

Traits

.isButtonState changes (loading, disabled) announced automaticallyCustom label via accessibilityLabel parameter

Related Components