skip to content

In React Native, how do Alert.alert buttons for a confirm-delete prompt behave differently on iOS and Android?

level: middleimportance: should knowfreq 44%

answer

  1. native dialog, returns nothing
  2. results only via button onPress
  3. Android: three slots, filled from the end
  4. destructive style is iOS-only
  5. prompt: one platform only

basics

~20 s

Alert.alert shows a native dialog and returns nothing; each button's onPress delivers the choice. iOS allows any number of buttons with cancel and destructive styles. Android keeps the first three, maps them from the end to positive, negative and neutral, and ignores style.

solid answer

~40 s

`Alert.alert(title, message, buttons, options)` asks the OS for its native dialog. It returns `void`, so you act in each button's `onPress`; to `await` the result, wrap it in a Promise. On iOS you can pass any number of buttons, mark them `'cancel'` or `'destructive'`, emphasise one with `isPreferred`, and force `userInterfaceStyle`. On Android only the first three buttons are kept, assigned from the end (last is positive, then negative, then neutral), and `style` is ignored. The dialog cannot be dismissed by tapping outside unless you pass `cancelable: true`, and then `onDismiss` reports it. For a confirm-delete, pass `[Cancel, Delete]`, with Delete marked destructive for iOS. `Alert.prompt` exists only on iOS and silently does nothing on Android.

code

typescript · 15 lines
typescript
import {Alert} from 'react-native';

export function confirmDeletePhoto(name: string): Promise<boolean> {
  return new Promise(resolve => {
    Alert.alert(
      'Delete photo?',
      `${name} will be removed from your backup.`,
      [
        {text: 'Cancel', style: 'cancel', onPress: () => resolve(false)},
        {text: 'Delete', style: 'destructive', onPress: () => resolve(true)},
      ],
      {cancelable: true, onDismiss: () => resolve(false)},
    );
  });
}

go deeper

for a junior

Recall the call shape, title, message and a buttons array with onPress, and that the choice arrives in a callback because Alert.alert returns nothing.

for a middle

Explain the platform mapping: Android keeps three buttons, assigns them from the end and ignores style, needs cancelable for tap-outside with onDismiss, and has no prompt.

for a senior

Wrap Alert in a promise that resolves on every exit path, including Android onDismiss, and know when a custom Modal is needed for branding, input or more than three choices.

for a principal

Set a house rule for when native alerts suffice and when a designed dialog is required, weighing platform familiarity against brand consistency and testability.

## What Alert is `Alert` from `react-native` is not a component you render. It is an imperative API that asks the operating system to show its **native alert dialog**. That makes it the fastest way to build a confirm-delete prompt, such as "Delete IMG_0042 from your backup?", and it explains its limits: you cannot style it, you cannot put a `View` inside it, and it behaves the way each platform's dialogs behave. ```text Alert.alert(title, message?, buttons?, options?) ``` - `title` is required. `message` is optional. - `buttons` is an array of `{text, onPress, style?, isPreferred?}`. If you omit it, you get a single OK button. - `options` holds per-platform settings. - **It returns `void`.** It does not block and returns no Promise. The user's choice arrives only through the `onPress` of the button they tapped. ## iOS behaviour - **Any number of buttons.** - **`style`** can be `'default'`, `'cancel'` or `'destructive'`. The system styles destructive buttons as destructive and cancel buttons as cancel. - **`isPreferred`** emphasises one button. - **`options.userInterfaceStyle`** can force `'light'` or `'dark'`. ## Android behaviour Android dialogs have up to three slots: **neutral, negative and positive**. React Native maps your array onto them: 1. It keeps **at most the first three** buttons; any further ones are **silently dropped**. 2. It assigns them **from the end**: the last becomes **positive**, the one before it **negative**, and the one before that **neutral**. 3. **`style` and `isPreferred` are ignored**, so a `'destructive'` button looks like any other. 4. By default the alert **cannot be dismissed by tapping outside**. Pass `options.cancelable: true` to allow it, and handle that dismissal in `options.onDismiss`, because no button's `onPress` fires in that case. | | iOS | Android | |---|---|---| | Button count | unlimited | first three kept | | `style: 'destructive'` | styled as destructive | ignored | | Tap outside to dismiss | not offered through `Alert` options | only with `cancelable: true` | | `onDismiss` option | not available | fires on dismissal without a button | | `Alert.prompt` | text-input alert | does nothing | ## Alert.prompt is iOS-only `Alert.prompt(title, message, callbackOrButtons, type, defaultValue, keyboardType, options)` shows a text-input alert on iOS, with types `'plain-text'`, `'secure-text'` and `'login-password'`. On Android the method body does nothing at all: no dialog, no error. A cross-platform "rename album" prompt therefore needs a custom `Modal` with a `TextInput`. ## Writing a confirm-delete that behaves on both platforms - Order buttons as `[Cancel, Delete]`. On Android that makes Delete the positive action, and on iOS the `'cancel'` and `'destructive'` styles handle the emphasis. - Put the deletion in Delete's `onPress`, and do nothing (or log) in Cancel's. - If Android dismissal by tapping outside is enabled, treat `onDismiss` as a cancel. - To use the result with `await`, wrap the call in a Promise that resolves from each button's `onPress` and from `onDismiss`. ## Smaller details that show up in reviews - **The title can be hidden.** Passing `null` or an empty string as the title hides it, which suits one-line confirmations. - **Button text on Android defaults in JavaScript.** When you pass no buttons, the Android path creates a single button labelled `'OK'` in JavaScript. A source comment notes that iOS localises its default in native code, so on Android pass your own localised label rather than relying on the default. - **A button tap always closes the alert.** Tapping any button fires that button's `onPress` and dismisses the alert, so an `Alert` cannot stay open to validate a choice. - **Only the tapped button's callback fires.** If a user dismisses an Android alert by tapping outside (with `cancelable: true`), none of the button callbacks run, only `onDismiss`. ## When to use a Modal instead Reach for a custom `Modal` when you need branding, a thumbnail of the photo being deleted, more than three choices on Android, text input on Android, or a layout you can test like any other component. `Alert` wins when a plain system dialog is exactly what the moment needs.

  • How would you build a cross-platform 'rename album' prompt in React Native?
    Not with `Alert.prompt`: it shows a text-input alert on iOS and does nothing on Android. Build a small `Modal` with a `TextInput` and Save and Cancel buttons, using `onRequestClose` for the Android back button. That also lets you validate the name inline.
  • Why can await Alert.alert(...) not be used to wait for the user's choice?
    `Alert.alert` returns `void`, not a Promise, so `await` resolves immediately while the dialog is still on screen. The choice arrives later through a button's `onPress` (or `onDismiss` on Android). Wrap the call in a Promise that resolves from those callbacks.

saying these in an interview costs you the question

  • Alert.alert returns a Promise with the pressed button.
  • Android shows every button passed to Alert.alert.
  • A 'destructive' button is shown in red on Android too.
  • Alert.prompt works on Android as well as iOS.
  • Android alerts can be dismissed by tapping outside by default.