Pressable
An unstyled clickable surface: button semantics - keyboard activation, focus ring, disabled state - with none of a button's looks. It carries no padding, margin, border, background, or font of its own, so it can wrap arbitrary content without shifting a single pixel of it.
Reach for this instead of putting onClick on a div or a styled Flex. Those are invisible
to keyboard and screen-reader users; this is not. Reach for Button
instead when you want something that looks like a button.
feedback picks what happens while the surface is held - nothing (the default), the content
dims, or the surface tints. Feedback is press-only, so hover styling stays entirely yours.
What it renders
A div by default. That is deliberate: a <button> may only contain phrasing content, so
it cannot legally wrap a link, another button, or block-level markup - exactly the things a
clickable card or row is made of. The div is given role="button", a tab stop, Enter/Space
activation, and aria-disabled, so it is announced and operated as a button regardless.
as | Element | Semantics |
|---|---|---|
| (default) | div | Shimmed - role, tabIndex, Enter/Space. |
"button" | button | Native. Use when the content is phrasing-only. |
| (any other tag) | that tag | Shimmed, same as the div. |
(href set) | a | Native link. No shim; Enter activates. |
as="button" is worth reaching for when the content is phrasing-only and you want the browser
rather than a shim to do the work.
Whichever element it renders, its text is not selectable: dragging across it or double-clicking
it presses rather than highlighting, matching a native button. Override with userSelect through
theme.components.Pressable.styleOverrides or a styled() wrapper if you are deliberately
wrapping selectable copy.
Usage
// A clickable row that lays out exactly as it would unwrapped.
<Pressable onClick={() => select(id)}>
<Flex flexDirection="row" alignItems="center" gap={2}>
<Icon name="folder" size="1.25rem" color="inherit" />
<span>Documents</span>
</Flex>
</Pressable>
// Dim the content while held.
<Pressable feedback="opacity" activeOpacity={0.4} onClick={onPress}>
<Avatar src={user.avatar} alt={user.name} />
</Pressable>
// Tint the surface while held - padding and radius are opt-in.
<Pressable feedback="highlight" color="secondary" p={2} borderRadius="md" onClick={onPress}>
<Typography as="span">Settings</Typography>
</Pressable>
// A native button - the content here is phrasing-only, so it is legal.
<Pressable as="button" onClick={onPress}>
<Typography as="span">Save</Typography>
</Pressable>
// Renders an anchor.
<Pressable href="/docs">Read the docs</Pressable>
Examples
Default
<Pressable>Press me</Pressable>
Opacity
<Pressable feedback="opacity">Hold to dim</Pressable>
Highlight
<Pressable feedback="highlight" p={2} borderRadius="md">Hold to tint</Pressable>
Wrapping Content
<Pressable feedback="highlight" p={2} borderRadius="md" width="16rem">
<Flex flexDirection="row" alignItems="center" gap={2} width="100%">
<Icon name="folder" size="1.25rem" color="inherit" />
<Typography as="span" variant="inherit" m={0}>
Documents
</Typography>
</Flex>
</Pressable>