UNPKG

consensys-ui

Version:

Consensys UI component library and design system

355 lines (266 loc) 9.62 kB
# Button Component The `<Button />` component provides a cross-platform button that adapts to both web and React Native environments while providing platform-native APIs for each. ## Installation ```bash pnpm add @consensys/ui ``` ## Usage Examples The Button component supports both web and native APIs through our [Dual API](#6--dual-api) and offers flexibility through our [Compound Components](#2--compound-components). ### Web-Specific Usage ```tsx import { Button } from '@consensys/ui'; function WebButton() { // Using web-specific APIs return ( <Button type="submit" onClick={(e) => console.log('Clicked!', e)} > Submit Form </Button> ); } ``` ### Native/Hybrid Usage ```tsx import { Button } from '@consensys/ui'; function NativeButton() { // Using React Native APIs return ( <Button onPress={(e) => console.log('Pressed!', e)} > <Button.Text>Press Me</Button.Text> </Button> ); } ``` > **Note**: Choose one API style and stick with it throughout your codebase. See the [Dual API](#6--dual-api) for more details. ## Component API Simple Usage: ```tsx <Button variant="solid" color="primary" icon={Figma}> Click Me </Button> ``` Compound Usage: ```tsx <Button variant="soft" color="primary" className="rounded-full"> <Button.Icon icon={Figma} className="text-primary-9" /> <Button.Text className="font-bold">Customized Button</Button.Text> <Button.Spinner className="animate-bounce" /> </Button> ``` ### `<Button />` The main Button component with various styling options. #### Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `variant` | `'elevated' \| 'solid' \| 'soft' \| 'outline' \| 'dashed' \| 'ghost'` | `'elevated'` | The visual style of the button | | `color` | `'neutral' \| 'primary' \| 'secondary' \| 'error' \| 'warning' \| 'success'` | `'neutral'` | The color scheme of the button | | `accentColor` | Same as `color` | - | Color to switch to on hover/press | | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the button | | `disabled` | `boolean` | `false` | Whether the button is disabled | | `loading` | `boolean` | `false` | Whether the button is in loading state | | `asChild` | `boolean` | `false` | Whether to replace the button with a different component | | `className` | `string` | - | Additional class names | Plus additional props based on platform: - Web: All [`HTMLButtonElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement) props ([`onClick`](https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event), [`type`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-type), etc.) - Native: All [`Pressable`](https://reactnative.dev/docs/pressable) props ([`onPress`](https://reactnative.dev/docs/pressable#onpress), [`onPressIn`](https://reactnative.dev/docs/pressable#onpressin), etc.) ### `<Button.Text />` Child component for button text. ```tsx // Simple usage <Button variant="solid" color="primary"> Click Me </Button> // Compound usage <Button variant="solid" color="primary"> <Button.Text>Button Text</Button.Text> </Button> ``` #### Props For props and styling options, see the [Text Component API](/packages/ui/src/components/text). ### `<Button.Icon />` An icon for the button. Can be placed before or after the text. ```tsx import { Figma } from 'lucide-react-native'; // Simple usage <Button variant="solid" color="primary" icon={Figma}> Click Me </Button> // Compound usage <Button variant="solid" color="primary"> <Button.Icon icon={Figma} /> <Button.Text>With Icon</Button.Text> </Button> ``` #### Props For props and styling options, see the [Icon Component API](/packages/ui/src/components/icon). ### `<Button.Spinner />` A loading spinner that automatically appears when the button's `loading` prop is true. > **Note:** When the `loading` prop is set to true, a default spinner will be shown automatically. Using Button.Spinner gives you more control over customization and placement. ```tsx import { Figma, Loader } from 'lucide-react-native'; // Simple usage <Button variant="solid" color="primary" loading> Loading... </Button> // Simple usage with fallback icon <Button variant="solid" color="primary" loading icon={Figma}> Loading... </Button> // Compound usage <Button variant="solid" color="primary" loading> <Button.Spinner loadingIcon={Loader} icon={Figma} /> <Button.Text>Loading</Button.Text> </Button> ``` The `Button.Spinner` component: - Shows when the parent Button has `loading={true}` - Displays the `loadingIcon` when loading, and the `icon` when not loading - Serves as both spinner and regular icon in one component #### Props For props and styling options, see the [Spinner Component API](/packages/ui/src/components/spinner). ### `<IconButton />` For buttons with only an icon, use the IconButton component: ```tsx import { IconButton } from '@consensys/ui'; import { Figma } from 'lucide-react-native'; // Web example <IconButton variant="solid" color="primary" size="md" icon={Figma} onClick={() => console.log('Icon clicked')} aria-label="Open Figma" /> // Native example <IconButton variant="solid" color="primary" size="md" icon={Figma} onPress={() => console.log('Icon pressed')} accessibilityLabel="Open Figma" /> ``` #### Props IconButton is a wrapper around Button with additional styling for icon-only use cases. See the [Button](#button) section above for all available props and compound parts. ## Styling Options ### Variants ```tsx <Button variant="elevated">Elevated</Button> <Button variant="solid">Solid</Button> <Button variant="soft">Soft</Button> <Button variant="outline">Outline</Button> <Button variant="dashed">Dashed</Button> <Button variant="ghost">Ghost</Button> ``` ### Colors ```tsx <Button color="neutral">Neutral</Button> <Button color="primary">Primary</Button> <Button color="secondary">Secondary</Button> <Button color="error">Error</Button> <Button color="warning">Warning</Button> <Button color="success">Success</Button> ``` ### Sizes ```tsx <Button size="sm">Small</Button> <Button size="md">Medium</Button> <Button size="lg">Large</Button> ``` ### Accent Colors Change the color on hover/press: ```tsx // Web example with hover effect <Button variant="soft" color="primary" accentColor="secondary" className="transition-colors duration-200" > Hover Me </Button> // React Native example with press effect <Button variant="soft" color="primary" accentColor="secondary" > <Button.Text>Press Me</Button.Text> </Button> ``` ### Disabled State ```tsx // Web example <Button disabled> Disabled Button </Button> // React Native example <Button disabled> <Button.Text>Disabled Button</Button.Text> </Button> ``` ### Events Each platform has its own event handling system: ```tsx import type { WebClickEvent, NativePressEvent } from '@consensys/ui'; // Web events <Button onClick={(e: WebClickEvent) => console.log('Clicked', e)} > Web Events </Button> // Native events <Button onPress={(e: NativePressEvent) => console.log('Pressed', e)} > <Button.Text>Native Events</Button.Text> </Button> ``` The component exports typed event interfaces that match their platform equivalents: - Web: [`HTMLButtonElement` events](https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement) like `onClick`, `onFocus` - Native: [`Pressable` events](https://reactnative.dev/docs/pressable) like `onPress`, `onPressIn` For details on typed events and the dual-API approach, see the [Dual API](#6--dual-api). ### Using `asChild` for Custom Elements The Button component supports the [Slot Pattern](../../../README.md#the-slot-pattern-aschild) via the `asChild` prop, allowing you to replace the button with a custom component: ```tsx // Web example with anchor <Button variant="solid" color="primary" asChild> <a href="https://example.com">Visit Website</a> </Button> // React Router example <Button variant="solid" color="primary" asChild> <Link to="/dashboard">Go to Dashboard</Link> </Button> // React Navigation example (React Native) <Button variant="solid" color="primary" asChild> <TouchableOpacity onPress={() => navigation.navigate('Details')}> <Text>Go to Details</Text> </TouchableOpacity> </Button> ``` ## Prop Mapping Button implements automatic prop mapping to support cross-platform development while maintaining platform-specific behavior: | Native Prop | Web Prop | Description | |-------------|----------|-------------| | `onPress` | `onClick` | Triggered when button is pressed/clicked | | `onPressIn` | `onMouseDown` | Triggered when press/mouse down begins | | `onPressOut` | `onMouseUp` | Triggered when press/mouse up ends | > While native props can be used in web environments, web props should never be used in native environments. For more details on our cross-platform approach, see the [Dual API](#6--dual-api). ## Accessibility The Button component automatically implements proper accessibility attributes for each platform: ### Accessibility Prop Mappings | Property | Web Implementation | Native Implementation | |----------|-------------------|----------------------| | Role | `role="button"` | `accessibilityRole="button"` | | Disabled | `aria-disabled={disabled}` | `accessibilityState={{ disabled }}` | | Loading | `aria-busy={loading}` | `accessibilityState={{ busy: loading }}` | When using `IconButton`, remember to provide descriptive labels: - Web: Use `aria-label="Description"` - Native: Use `accessibilityLabel="Description"`