@xsolla/xui-button
v0.103.0
Published
A cross-platform React button component with primary/secondary variants, multiple color tones, sizes, loading states, and icon support. Works on both React (web) and React Native.
Readme
Button
A cross-platform React button component with primary/secondary variants, multiple color tones, sizes, loading states, and icon support. Works on both React (web) and React Native.
Installation
npm install @xsolla/xui-button
# or
yarn add @xsolla/xui-buttonDemo
Basic Button
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function BasicButton() {
return (
<Button onPress={() => console.log('Pressed!')}>
Click me
</Button>
);
}Button Variants
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function ButtonVariants() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="tertiary">Tertiary</Button>
</div>
);
}Button Tones
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function ButtonTones() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<Button tone="brand">Brand</Button>
<Button tone="brandExtra">Brand Extra</Button>
<Button tone="alert">Alert</Button>
<Button tone="mono">Mono</Button>
</div>
);
}Button Sizes
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function ButtonSizes() {
return (
<div style={{ display: 'flex', gap: 16, alignItems: 'center' }}>
<Button size="xs">Extra Small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="xl">Extra Large</Button>
</div>
);
}Button with Icons
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
import { Plus, ChevronDown, FileDownloadOut } from '@xsolla/xui-icons-base';
import { ArrowRight } from '@xsolla/xui-icons';
export default function ButtonWithIcons() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<Button iconLeft={<Plus />}>
Add Item
</Button>
<Button iconRight={<ArrowRight />}>
Next Step
</Button>
<Button
iconLeft={<FileDownloadOut />}
iconRight={<ChevronDown />}
>
Download
</Button>
</div>
);
}Loading Button
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function LoadingButton() {
const [loading, setLoading] = React.useState(false);
const handlePress = () => {
setLoading(true);
setTimeout(() => setLoading(false), 2000);
};
return (
<Button loading={loading} onPress={handlePress}>
{loading ? 'Processing...' : 'Submit'}
</Button>
);
}Anatomy
Import the component and use it directly:
import { Button, IconButton, FlexButton, ButtonGroup } from '@xsolla/xui-button';
import { Plus } from '@xsolla/xui-icons-base';
// Basic button
<Button>Label</Button>
// Icon-only button
<IconButton icon={<Plus />} aria-label="Add item" />
// Flexible styling button
<FlexButton variant="brand">Label</FlexButton>
// Group of buttons
<ButtonGroup>
<Button>First</Button>
<Button>Second</Button>
</ButtonGroup>Examples
Full Width Button
Use the fullWidth prop to make the button span the entire container width.
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function FullWidthButton() {
return (
<div style={{ width: 300 }}>
<Button fullWidth>Full Width Button</Button>
</div>
);
}Disabled Button
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function DisabledButton() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<Button disabled>Disabled Primary</Button>
<Button variant="secondary" disabled>Disabled Secondary</Button>
</div>
);
}Icon Button
Use IconButton for buttons that contain only an icon.
import * as React from 'react';
import { IconButton } from '@xsolla/xui-button';
import { Plus, TrashCan } from '@xsolla/xui-icons-base';
import { Settings } from '@xsolla/xui-icons';
export default function IconButtonExample() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<IconButton
icon={<Plus />}
aria-label="Add"
size="md"
/>
<IconButton
icon={<TrashCan />}
aria-label="Delete"
tone="alert"
/>
<IconButton
icon={<Settings />}
aria-label="Settings"
variant="secondary"
/>
</div>
);
}Button Group
Use ButtonGroup to group related buttons together.
import * as React from 'react';
import { Button, ButtonGroup } from '@xsolla/xui-button';
export default function ButtonGroupExample() {
return (
<ButtonGroup orientation="horizontal" size="md">
<Button variant="secondary">Cancel</Button>
<Button>Confirm</Button>
</ButtonGroup>
);
}Vertical Button Group
import * as React from 'react';
import { Button, ButtonGroup } from '@xsolla/xui-button';
export default function VerticalButtonGroup() {
return (
<ButtonGroup orientation="vertical" size="md">
<Button fullWidth>Option 1</Button>
<Button fullWidth>Option 2</Button>
<Button fullWidth>Option 3</Button>
</ButtonGroup>
);
}Flex Button
FlexButton provides more flexible styling options with different background modes.
import * as React from 'react';
import { FlexButton } from '@xsolla/xui-button';
import { Link } from '@xsolla/xui-icons-base';
export default function FlexButtonExample() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<FlexButton variant="brand" background>
With Background
</FlexButton>
<FlexButton variant="brand">
Text Only
</FlexButton>
<FlexButton variant="tertiary" iconLeft={<Link />}>
Link Style
</FlexButton>
</div>
);
}Form Submit Button
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
export default function FormSubmitButton() {
return (
<form onSubmit={(e) => {
e.preventDefault();
console.log('Form submitted');
}}>
<Button type="submit">Submit Form</Button>
</form>
);
}Button with Sublabel
Use the sublabel prop to add secondary text inline with the main label.
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
import { Apple } from '@xsolla/xui-icons-brand';
export default function ButtonWithSublabel() {
return (
<Button
iconLeft={<Apple />}
sublabel="$39.99"
labelAlignment="left"
>
Buy Now
</Button>
);
}Button with Divider
The divider prop controls whether a separator line appears between icons and content.
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
import { ArrowRight } from '@xsolla/xui-icons-base';
export default function ButtonWithDivider() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<Button iconRight={<ArrowRight />} divider>
With Divider
</Button>
<Button iconRight={<ArrowRight />} divider={false}>
No Divider
</Button>
</div>
);
}Button with Custom Content
Use customContent to add badges, tags, or other elements inside the button.
import * as React from 'react';
import { Button } from '@xsolla/xui-button';
import { Tag } from '@xsolla/xui-tag';
import { ArrowRight } from '@xsolla/xui-icons-base';
export default function ButtonWithCustomContent() {
return (
<Button
iconRight={<ArrowRight />}
customContent={<Tag size="sm">5x</Tag>}
divider
>
Claim Reward
</Button>
);
}Tertiary Variant
The tertiary variant provides a minimal, text-like button style.
import * as React from 'react';
import { Button, IconButton } from '@xsolla/xui-button';
import { Settings } from '@xsolla/xui-icons-base';
export default function TertiaryButtons() {
return (
<div style={{ display: 'flex', gap: 16 }}>
<Button variant="tertiary">Learn More</Button>
<IconButton
variant="tertiary"
icon={<Settings />}
aria-label="Settings"
/>
</div>
);
}API Reference
Button
The main button component. Renders a semantic <button> element.
Button Props:
| Prop | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| children | ReactNode | - | The button label content. |
| variant | "primary" \| "secondary" \| "tertiary" | "primary" | The visual style variant. |
| tone | "brand" \| "brandExtra" \| "alert" \| "mono" | "brand" | The color tone of the button. |
| size | "xl" \| "lg" \| "md" \| "sm" \| "xs" | "md" | The size of the button. |
| disabled | boolean | false | Whether the button is disabled. |
| loading | boolean | false | Whether to show loading spinner. Disables interaction when true. |
| onPress | () => void | - | Callback fired when button is pressed. |
| iconLeft | ReactNode | - | Icon to display on the left side. |
| iconRight | ReactNode | - | Icon to display on the right side. |
| divider | boolean | true when icon present | Whether to show divider between icon and label. |
| sublabel | string | - | Secondary label text displayed inline with main label at 40% opacity. |
| labelIcon | ReactNode | - | Small icon displayed directly next to the label text. |
| labelAlignment | "left" \| "center" | "center" | Alignment of the label content within the button. |
| customContent | ReactNode | - | Custom content slot for badges, tags, or other elements. |
| fullWidth | boolean | false | Whether button should span full container width. |
| type | "button" \| "submit" \| "reset" | "button" | The HTML button type attribute. |
| aria-label | string | - | Accessible label for the button. |
| aria-describedby | string | - | ID of element that describes the button. |
| aria-expanded | boolean | - | Indicates if controlled element is expanded. |
| aria-haspopup | boolean \| "menu" \| "listbox" \| "tree" \| "grid" \| "dialog" | - | Indicates popup type triggered by button. |
| aria-pressed | boolean \| "mixed" | - | Indicates pressed state for toggle buttons. |
| aria-controls | string | - | ID of element controlled by this button. |
| testID | string | - | Test identifier for testing frameworks. |
| id | string | - | HTML id attribute. |
IconButton
A button variant that displays only an icon. Requires aria-label for accessibility.
IconButton Props:
| Prop | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| icon | ReactNode | - | Required. The icon to display. |
| aria-label | string | - | Required. Accessible label for the button. |
| variant | "primary" \| "secondary" \| "tertiary" | "primary" | The visual style variant. |
| tone | "brand" \| "brandExtra" \| "alert" \| "mono" | "brand" | The color tone of the button. |
| size | "xl" \| "lg" \| "md" \| "sm" \| "xs" | "md" | The size of the button. |
| disabled | boolean | false | Whether the button is disabled. |
| loading | boolean | false | Whether to show loading spinner. |
| onPress | () => void | - | Callback fired when button is pressed. |
| type | "button" \| "submit" \| "reset" | "button" | The HTML button type attribute. |
FlexButton
A flexible button with more granular control over background and styling.
FlexButton Props:
| Prop | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| children | ReactNode | - | The button label content. |
| variant | "brand" \| "primary" \| "secondary" \| "tertiary" \| "brandExtra" \| "inverse" | "brand" | The visual style variant. |
| size | "xl" \| "lg" \| "md" \| "sm" \| "xs" | "md" | The size of the button. |
| background | boolean | false | Whether to show background fill. |
| disabled | boolean | false | Whether the button is disabled. |
| loading | boolean | false | Whether to show loading spinner. |
| iconLeft | ReactNode | - | Icon to display on the left side. |
| iconRight | ReactNode | - | Icon to display on the right side. |
| onPress | () => void | - | Callback fired when button is pressed. |
| type | "button" \| "submit" \| "reset" | "button" | The HTML button type attribute. |
ButtonGroup
A container for grouping related buttons together.
ButtonGroup Props:
| Prop | Type | Default | Description |
| :--- | :--- | :------ | :---------- |
| children | ReactNode | - | Required. Button children to group. |
| orientation | "horizontal" \| "vertical" | "horizontal" | Layout direction of the buttons. |
| size | "xl" \| "lg" \| "md" \| "sm" \| "xs" | "md" | Size applied to the group spacing. |
| gap | number | - | Custom gap between buttons (overrides size default). |
| description | string | - | Description text shown below the group. |
| error | string | - | Error message (replaces description when present). |
| aria-label | string | - | Accessible label for the button group. |
| aria-labelledby | string | - | ID of element labeling the group. |
| aria-describedby | string | - | ID of element describing the group. |
| id | string | - | HTML id attribute. |
| testID | string | - | Test identifier for testing frameworks. |
ButtonGroup Gap Defaults:
| Size | Vertical Gap | Horizontal Gap | | :--- | :----------- | :------------- | | xl | 16 | 16 | | lg | 16 | 16 | | md | 12 | 16 | | sm | 8 | 12 | | xs | 4 | 12 |
Theming
Button components use the design system theme for colors and sizing:
// Colors accessed via theme
theme.colors.control.[tone].[variant].bg // Background color
theme.colors.control.[tone].[variant].bgHover // Hover background
theme.colors.control.[tone].[variant].bgPress // Pressed background
theme.colors.control.[tone].[variant].text // Text color
theme.colors.control.[tone].[variant].border // Border color
// Sizing accessed via theme
theme.sizing.button(size).height
theme.sizing.button(size).paddingHorizontal
theme.sizing.button(size).fontSize
theme.sizing.button(size).iconSize
// Border radius
theme.radius.buttonAccessibility
- All buttons use semantic
<button>elements IconButtonrequiresaria-labelfor screen reader supportButtonGroupusesrole="group"with proper ARIA attributes- Focus indicators follow WCAG guidelines
- Disabled buttons are properly announced to assistive technology
- Loading state is communicated via
aria-busyattribute
