Skip to main content

IconButton

Icon buttons help people take supplementary actions with a single tap. Follows the Material Design 3 Icon Button specification.

The icon and selectedIcon props accept three forms — a string name (resolved via MaterialCommunityIcons by default), a pre-rendered React element from any icon library, or a render function that receives the resolved { size, color }. See the Icons guide for full details, including how to register a global iconResolver for Lucide, SF Symbols, or custom SVGs.

Usage

import { IconButton } from '@rootnative/components'
import { ThemeProvider } from '@rootnative/core'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { View } from 'react-native'

export default function App() {
return (
<SafeAreaProvider>
<ThemeProvider>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<IconButton
icon="heart-outline"
accessibilityLabel="Favorite"
onPress={() => {}}
/>
</View>
</ThemeProvider>
</SafeAreaProvider>
)
}

Variants

VariantUse case
filledHigh emphasis, filled container
tonalMedium emphasis, tonal container
outlinedMedium emphasis, outlined border
standardLow emphasis, no container

Sizes

Five MD3 Expressive sizes. s is the default.

sizeHeightIcon
xs32dp20dp
s40dp24dp
m56dp24dp
l96dp32dp
xl136dp40dp
import { IconButton } from '@rootnative/components'
import { ThemeProvider } from '@rootnative/core'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { View } from 'react-native'

export default function App() {
return (
<SafeAreaProvider>
<ThemeProvider>
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 12 }}>
<IconButton icon="star" size="xs" accessibilityLabel="Star" onPress={() => {}} />
<IconButton icon="star" size="s" accessibilityLabel="Star" onPress={() => {}} />
<IconButton icon="star" size="m" accessibilityLabel="Star" onPress={() => {}} />
</View>
</ThemeProvider>
</SafeAreaProvider>
)
}

Width and shape

width trades horizontal padding at a fixed height — 'narrow', 'uniform' (default), or 'wide'. At size="s" that is 32 / 40 / 52dp wide.

shape controls the resting container: 'round' (default) rests as a circle/pill, 'square' rests at a size-dependent corner. Toggle buttons invert their shape when selected, so a round toggle squares off to signal the change.

<IconButton icon="star" width="wide" accessibilityLabel="Star" />
<IconButton icon="star" shape="square" accessibilityLabel="Star" />

Bring your own icon library

import { IconButton } from '@rootnative/components'
import { Heart } from 'lucide-react-native'

<IconButton
icon={({ size, color }) => <Heart size={size} color={color} />}
accessibilityLabel="Like"
/>

The render-function form receives the size and color the IconButton would have given to its default icon (24dp at the default s size, plus the variant + state color), so the icon stays in sync with size/variant changes automatically.

Toggle Mode

Use selected and selectedIcon for toggle behavior:

import { IconButton } from '@rootnative/components'
import { ThemeProvider } from '@rootnative/core'
import { SafeAreaProvider } from 'react-native-safe-area-context'
import { useState } from 'react'
import { View } from 'react-native'

export default function App() {
const [liked, setLiked] = useState(false)
return (
<SafeAreaProvider>
<ThemeProvider>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<IconButton
icon="heart-outline"
selectedIcon="heart"
selected={liked}
onPress={() => setLiked(!liked)}
accessibilityLabel={liked ? 'Unlike' : 'Like'}
/>
</View>
</ThemeProvider>
</SafeAreaProvider>
)
}

Props

PropTypeDefaultRequiredDescription
iconIconSource-YesIcon to display. Accepts a string name (resolved via the theme's `iconResolver`, defaulting to `MaterialCommunityIcons`), a pre-rendered element, or a render function that receives `{ size, color }`.
selectedIconIconSource-NoIcon to display when `selected` is `true` (toggle mode).
iconColorstring-NoOverrides the automatic icon color derived from the variant and state.
contentColorstring-NoOverride the content (icon) color. Takes precedence over `iconColor` when both are provided.
containerColorstring-NoOverride the container (background) color. State-layer colors (hover, press) are derived automatically.
styleStyleProp<ViewStyle>-NoStyle applied to the root container. Static form only — the function form `(state) => style` is not supported because the component drives its container background through Reanimated. Use `containerColor` / `contentColor` for state-aware styling.
onPress() => void-NoCalled when the button is pressed.
disabledbooleanNoDisables the button.
variantenumfilledNoVisual style variant.
selectedboolean-NoEnables toggle mode. The button changes appearance based on selected/unselected state.
sizeenumsNoMD3 Expressive size — one of `'xs' | 's' | 'm' | 'l' | 'xl'`. Sets container height and icon size.
widthenumuniformNoWidth variant. `'uniform'` is a square container; `'narrow'`/`'wide'` adjust horizontal padding around the icon.
shapeenumroundNoContainer shape. `'round'` is a pill/circle; `'square'` rests at a size-dependent corner. Toggle buttons invert the shape when selected.
accessibilityLabelstring-YesRequired — icon-only buttons must have a label for screen readers.
onKeyDown(event: { nativeEvent: { key?: string; }; }) => void-No-