skip to content

In React Native, how do you keep a boarding pass's buttons at least 44pt on iOS and 48dp on Android as text grows?

level: middleimportance: should knowfreq 30%

answer

  1. style units are pt and dp already
  2. minHeight and minWidth, not height
  3. padding around small icons
  4. one value, 48, satisfies both
  5. spacing between targets matters too

basics

~20 s

Give the pressable area minHeight and minWidth of at least 48, which React Native's density-independent units make at least 44pt on iOS and 48dp on Android, pad small icons, and never fix the height, so targets grow with their text.

solid answer

~50 s

React Native style numbers are density-independent, points on iOS and dp on Android, so `minHeight: 48` and `minWidth: 48` on a `Pressable` satisfy both Apple's 44-point and Android's 48dp guidance with one value. I use `minHeight` rather than `height`, so a button whose label grows at large text sizes grows with it instead of clipping. A small icon button, such as the share icon on a boarding pass, gets padding around a 24-point icon to reach the minimum, rather than a bigger icon. I leave space between adjacent targets so a larger finger does not hit two, and I check the result at the largest text setting on devices, where rows of buttons are most likely to wrap or squeeze. `hitSlop` can extend a touch area without changing layout, but the visible size is the better default.

code

tsx · 22 lines
tsx
import {Pressable, StyleSheet, Text, View} from 'react-native';

export function PassActions({onShare, onAddToWallet}: {onShare: () => void; onAddToWallet: () => void}) {
  return (
    <View style={styles.row}>
      <Pressable onPress={onAddToWallet} style={styles.button}>
        <Text style={styles.label}>Add to wallet</Text>
      </Pressable>
      <Pressable onPress={onShare} accessibilityLabel="Share boarding pass" style={styles.iconButton}>
        <Text style={styles.icon}>{'\u2197'}</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  row: {flexDirection: 'row', flexWrap: 'wrap', gap: 12},
  button: {minHeight: 48, paddingHorizontal: 16, paddingVertical: 12, justifyContent: 'center'},
  label: {fontSize: 16},
  iconButton: {minWidth: 48, minHeight: 48, alignItems: 'center', justifyContent: 'center'},
  icon: {fontSize: 20},
});

go deeper

for a junior

Recall the 44-point iOS and 48dp Android minimums, and that minHeight and minWidth of 48 meet both in React Native units.

for a middle

Explain why minHeight rather than height keeps targets usable as text grows, and how padding brings icon buttons to the minimum.

for a senior

Show how you check targets at the largest text size on devices, handle rows that must wrap, and decide when hitSlop is an acceptable exception.

for a principal

Bake minimum target sizes into shared button and icon-button components so feature teams cannot ship undersized controls.

## The guidance Both platforms publish a minimum size for touch targets: **44 by 44 points** in Apple's guidelines and **48 by 48 dp** in Android's Material guidance. The React Native docs make the same recommendation in their user-experience advice: interactive elements should be 44x44 or larger. Small targets are hard for everyone to hit, and much harder for people with tremors, limited dexterity or low vision. ## Units in React Native A React Native style number such as `minHeight: 48` is **density-independent**: it is measured in points on iOS and in dp on Android, not in physical pixels. That means one value works across devices of different densities, and **48 meets both minimums**, since 48 points is above Apple's 44. ## Sizing buttons that contain text A button with a text label must meet the minimum at the default text size **and** keep growing when the user picks larger text: - Use **`minHeight`** and **`minWidth`**, not `height` and `width`. A fixed `height: 48` clips the label once the text grows; `minHeight: 48` starts at the minimum and grows. - Use **vertical padding** around the label so the tap area is comfortable, and let the label wrap if the button is narrow. - In a row of buttons, allow the row to **wrap or stack** at large text sizes instead of squeezing each button below the minimum. ## Sizing icon-only buttons Icon buttons are the usual offenders: a 24-point share icon on the boarding pass is a 24-point target unless something makes it larger. 1. Wrap the icon in a `Pressable` with `minWidth: 48` and `minHeight: 48`. 2. Centre the icon with `alignItems` and `justifyContent`. 3. Give the button an accessibility label, because it has no visible text. `hitSlop` on `Pressable` can extend the touch area beyond the visible bounds without changing layout. It is useful when the design cannot grow, but a visible target of the right size is the better default because it also tells users where to tap. ## Spacing Size alone is not enough: two 48-point targets placed edge to edge are easy to confuse. Leave space between adjacent actions, for example with `gap` on the row, especially for destructive pairs such as "Remove pass" next to "Share". ## Checking it | Check | How | |---|---| | minimum size | log the element's size from `onLayout` during development, or measure it on screen | | growth with text | set the largest system text size and confirm labels are not clipped | | rows of buttons | confirm they wrap or stack rather than shrinking at large sizes | | icon buttons | confirm each has a label and a 48-point area | Do the pass on real iOS and Android devices at the largest text setting, because a row that fits at the default size is exactly the one that squeezes its buttons at large sizes. ## Common mistakes - `height: 44` on a text button, which clips at large text sizes. - A 24-point icon with no padding, relying on users to be precise. - Relying on `hitSlop` for every small target, so the visible layout still suggests a tiny control. - Packing four actions into one row that cannot wrap.

  • Why is minHeight: 48 enough for both platforms when Apple guidelines ask for 44 and Android for 48?
    React Native style numbers are points on iOS and dp on Android, both density-independent. 48 points exceeds Apple's 44-point minimum, and 48 dp meets Android's, so one value satisfies both without `Platform.select`.

saying these in an interview costs you the question

  • React Native style numbers are physical pixels, so targets need scaling by pixel density.
  • height: 44 on a text button is enough because it meets the minimum.
  • A 24-point icon is fine as a target because users can tap precisely.
  • hitSlop should replace visible target size everywhere.
  • Two adjacent 48-point targets need no space between them.