The Actionable component is a low-level utility that provides a consistent foundation for interactive elements. It handles the complexity of rendering buttons, links, or custom elements with proper accessibility attributes and focus management.
Basic Usage
import { Actionable } from 'reshaped';
// Renders as button
<Actionable onClick={() => console.log('clicked')}>
Click me
</Actionable>
// Renders as link
<Actionable href="/about">
About
</Actionable>
// Renders as span
<Actionable>
Static content
</Actionable>
With Custom Element
import { Actionable } from 'reshaped';
function Example() {
return (
<Actionable
as="div"
onClick={() => {}}
>
Custom element
</Actionable>
);
}
With Focus Ring
import { Actionable, View } from 'reshaped';
function FocusableCard() {
return (
<Actionable
insetFocus
borderRadius="inherit"
onClick={() => {}}
>
<View
padding={4}
borderRadius="large"
backgroundColor="neutral-faded"
>
Focusable card content
</View>
</Actionable>
);
}
onClick
(event: MouseEvent) => void
Click handler - causes component to render as a button
Link URL - causes component to render as an anchor element
Disable the interactive element
Enable a minimum required touch hitbox for better mobile accessibility
Take up the full width of its parent
Enable a focus ring inside the element bounds
Don’t show a focus ring on focus, can be used when it is within a container with a focus ring
Apply the focus ring to the child and rely on its border radius
HTML element to render as
Custom render function for complete control over the rendered element
type
'button' | 'submit' | 'reset'
Button type attribute (only applies when rendering as button)
Stop event propagation on click
Content to render inside the actionable element
Additional classname for the root element
Additional attributes for the element
When to Use
- Custom Interactive Components: Building custom buttons, cards, or interactive elements
- Polymorphic Elements: Need element to render as button, link, or other based on props
- Focus Management: Require custom focus ring behavior
- Accessibility: Ensure proper keyboard navigation and screen reader support
- Touch Targets: Mobile-first designs requiring minimum touch target sizes
Composition Patterns
Interactive Card
import { Actionable, View, Text, Stack } from 'reshaped';
function InteractiveCard({ title, description, onClick }) {
return (
<Actionable
onClick={onClick}
insetFocus
borderRadius="inherit"
>
<View
padding={4}
borderRadius="medium"
backgroundColor="elevated"
borderColor="neutral-faded"
borderWidth={1}
>
<Stack gap={2}>
<Text variant="title-5" weight="medium">{title}</Text>
<Text color="neutral">{description}</Text>
</Stack>
</View>
</Actionable>
);
}
Link with Custom Styling
import { Actionable, Text } from 'reshaped';
function CustomLink({ href, children }) {
return (
<Actionable
href={href}
disableFocusRing
>
<Text color="primary" weight="medium">
{children}
</Text>
</Actionable>
);
}
Mobile Touch Target
import { Actionable, Icon } from 'reshaped';
function IconButton({ icon, onClick, label }) {
return (
<Actionable
onClick={onClick}
touchHitbox
attributes={{ 'aria-label': label }}
>
<Icon svg={icon} size={5} />
</Actionable>
);
}
Disabled State
import { Actionable, View, Text } from 'reshaped';
function DisabledButton({ disabled, onClick, children }) {
return (
<Actionable
disabled={disabled}
onClick={onClick}
>
<View
padding={3}
backgroundColor={disabled ? 'neutral-faded' : 'primary'}
borderRadius="medium"
>
<Text color={disabled ? 'disabled' : 'white'}>
{children}
</Text>
</View>
</Actionable>
);
}
Full Width Action
import { Actionable, View, Text } from 'reshaped';
function FullWidthButton({ children, onClick }) {
return (
<Actionable
fullWidth
onClick={onClick}
>
<View
padding={4}
backgroundColor="primary"
borderRadius="medium"
align="center"
>
<Text color="white" weight="medium">{children}</Text>
</View>
</Actionable>
);
}
Custom Render Function
import { Actionable } from 'reshaped';
function CustomActionable() {
return (
<Actionable
onClick={() => {}}
render={(props) => (
<article {...props} data-custom="true">
Custom rendered element
</article>
)}
/>
);
}
Preventing Event Propagation
import { Actionable, View } from 'reshaped';
function NestedAction({ onParentClick, onChildClick }) {
return (
<Actionable onClick={onParentClick}>
<View padding={4}>
Parent clickable area
<Actionable
stopPropagation
onClick={onChildClick}
>
<View padding={2} backgroundColor="primary">
Child action (stops propagation)
</View>
</Actionable>
</View>
</Actionable>
);
}