Skip to content

Button

Buttons are the primary way users interact with Synchronicity applications. They trigger actions, submit forms, and navigate between screens.


The primary button is used for the most important action on a screen. Use sparingly—typically one per view.

<Button variant="primary" onPress={handleCast}>
Cast Hexagram
</Button>

Usage: Main CTAs, form submissions, primary actions

Secondary buttons are for supporting actions that don’t need visual priority.

<Button variant="secondary" onPress={handleSave}>
Save Reading
</Button>

Usage: Secondary actions, alternatives to primary

Ghost buttons are the most subtle. Use for tertiary actions or navigation.

<Button variant="ghost" onPress={handleLearnMore}>
Learn More
</Button>

Usage: Tertiary actions, cancel buttons, navigation

For dangerous or irreversible actions.

<Button variant="destructive" onPress={handleDelete}>
Delete Reading
</Button>

Usage: Delete, remove, disconnect actions


SizeHeightFont SizeUsage
sm36px13pxCompact spaces, toolbars
md44px15pxDefault, most cases
lg52px17pxHero sections, primary CTAs
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>

Hover over the button above to see the hover state with subtle glow effect.

<Button disabled>Cannot Press</Button>
<Button loading>Processing</Button>

Icons can be placed before or after the button label.

<Button icon={<CastIcon />} iconPosition="left">
Cast Now
</Button>
<Button icon={<ShareIcon />} iconPosition="right">
Share
</Button>

For icon-only buttons, always include an accessibility label.

<Button
icon={<MenuIcon />}
accessibilityLabel="Open menu"
/>

<Button fullWidth>Full Width Button</Button>

PropTypeDefaultDescription
variant'primary' | 'secondary' | 'ghost' | 'destructive''primary'Visual style
size'sm' | 'md' | 'lg''md'Button size
disabledbooleanfalseDisable interaction
loadingbooleanfalseShow loading state
iconReactNode-Icon element
iconPosition'left' | 'right''left'Icon placement
fullWidthbooleanfalseExpand to container
onPress() => void-Press handler
accessibilityLabelstring-Screen reader label
haptic'light' | 'medium' | 'heavy''light'Haptic feedback
import { button } from '@synchronicity/tokens/components';
// Colors
button.primary.background // #d4af37
button.primary.text // #0a0a0f
button.secondary.border // #d4af37
// Sizing
button.height.md // 44
button.padding.horizontal.md // 16
button.borderRadius // 8
// Typography
button.fontSize.md // 15
button.fontWeight // '600'

  • Use primary buttons for the main action on each screen
  • Provide clear, action-oriented labels (“Cast Hexagram”, not “Submit”)
  • Include haptic feedback for tactile response
  • Maintain minimum touch target (44x44 points)
  • Use multiple primary buttons in the same view
  • Use vague labels like “Click Here” or “OK”
  • Disable buttons without explanation
  • Use destructive styling for non-destructive actions

  • Touch target: Minimum 44x44 points
  • Color contrast: 9.4:1 for gold on dark (AAA compliant)
  • Focus indicator: 2px gold outline with offset
  • Screen reader: Announces button role and label
  • Disabled state: Reduced opacity (0.5), not just color change
<Button
onPress={handleAction}
accessibilityLabel="Cast a new hexagram using three coins"
accessibilityHint="Double tap to begin casting"
>
Cast Hexagram
</Button>

import { Button } from '@synchronicity/react-native';
import { useState } from 'react';
function CastingScreen() {
const [isLoading, setIsLoading] = useState(false);
const handleCast = async () => {
setIsLoading(true);
try {
await castHexagram();
} finally {
setIsLoading(false);
}
};
return (
<View style={styles.container}>
<Button
variant="primary"
size="lg"
loading={isLoading}
onPress={handleCast}
haptic="medium"
fullWidth
>
{isLoading ? 'Casting...' : 'Cast Hexagram'}
</Button>
<Button
variant="ghost"
onPress={goBack}
style={{ marginTop: 16 }}
>
Cancel
</Button>
</View>
);
}