Skip to content

Apple button ​

AppleButton is a JavaScript button that renders the Sign in with Apple appearance on iOS, Android, and web. It draws the Apple mark and the official label itself, so the look is identical on every platform and stays configurable (style, type, size, corner radius), and it can run the whole sign-in on press. This page lets you try the options live, lists every prop, and explains when to take over the press with onPress.

buttonStyle
buttonType
<AppleButton buttonStyle="black" buttonType="signIn" cornerRadius={8} height={48} onSuccess={handleCredential} />

Basic use ​

With no onPress, the button calls AppleAuth.signIn() for you, shows a spinner while it runs, and reports the outcome through onSuccess, onCancel, and onError.

SignIn.tsx
tsx
import { AppleButton } from 'expo-apple-sign-in'
import type { ReactElement } from 'react'
import { Alert } from 'react-native'

export function SignIn(): ReactElement {
  return (
    <AppleButton
      buttonType="continue"
      onSuccess={(credential) => {
        Alert.alert('Signed in', `Apple user ${credential.user.id ?? 'unknown'}`)
      }}
      onError={(error) => {
        Alert.alert('Sign in failed', `${error.code}: ${error.message}`)
      }}
    />
  )
}

A dismissed sheet calls onCancel and never onError. Configure Android and web once with AppleAuth.configure, as described in Usage.

Props ​

PropTypeDefaultDescription
onPress() => voidnoneCustom press handler. When set, the button does not call AppleAuth.signIn() and never calls onSuccess, onError, or onCancel.
onSuccess(credential: AppleCredential) => voidnoneCalled with the credential after a successful built-in sign-in.
onError(error: AppleAuthError) => voidnoneCalled when the built-in sign-in fails for any reason except a cancel.
onCancel() => voidnoneCalled when the person dismisses the Apple sheet.
buttonStyle'black' | 'white' | 'whiteOutline''black'Color scheme of the button.
buttonType'signIn' | 'continue' | 'signUp''signIn'Picks the official label.
labelstringlabel of buttonTypeReplaces the label text.
cornerRadiusnumber8Corner radius in points.
heightnumber48Button height. APPLE_BUTTON_HEIGHT exports the default.
widthnumber or a percentage string'100%'Button width, for example 240 or '80%'.
disabledbooleanfalseDisables presses and dims the button to 50% opacity.
styleStyleProp<ViewStyle>noneExtra styles applied after the defaults, so they win.
textStyleStyleProp<TextStyle>noneExtra styles for the label text.
childrenReactNodenoneReplaces the Apple mark and the label with your own content.
accessibilityLabelstringthe label textText that screen readers announce for the button.
accessibilityHintstringnoneExtra description that screen readers announce after the label.

AppleButton also accepts every other Pressable prop, such as testID or onLongPress, and passes it to the underlying Pressable. The button sets accessibilityRole to 'button' and reports accessibilityState with disabled and busy, so busy is true while its own sign-in runs. It replaces any accessibilityRole or accessibilityState you pass.

The button also sets a minimum width of 200 points, horizontal padding of 16 points, and a pressed opacity of 0.86.

Styles and types ​

buttonStyle selects one of three palettes.

ValueBackgroundMark and textBorder
black#000000#ffffffnone
white#ffffff#000000none
whiteOutline#ffffff#000000black, two hairline widths

buttonType selects the official label and the accessibility label.

ValueLabel
signInSign in with Apple
continueContinue with Apple
signUpSign up with Apple

The type only changes the label, so pick the one that matches the screen.

Choose between onSuccess and onPress ​

The built-in flow fits when you want the credential and handle the rest yourself. It stops fitting when you use an adapter such as signInWithSupabase, signInWithClerk, or signInWithFirebase. An adapter calls AppleAuth.signIn itself, then exchanges the token with your provider. If you call an adapter from onSuccess, the person sees the Apple sheet twice.

Adapters belong in onPress

Pass the adapter call to onPress and never call it from onSuccess. With onPress set, the button leaves the sign-in to you, so it also stops tracking the busy state: use disabled while your call runs.

SignInWithSupabase.tsx
tsx
import { createClient } from '@supabase/supabase-js'
import { AppleButton, isCancelledError, signInWithSupabase } from 'expo-apple-sign-in'
import { useState } from 'react'
import type { ReactElement } from 'react'
import { Alert } from 'react-native'

const supabase = createClient('https://example.supabase.co', 'public-anon-key')

export function SignInWithSupabase(): ReactElement {
  const [isSigningIn, setIsSigningIn] = useState(false)

  async function handlePress(): Promise<void> {
    setIsSigningIn(true)
    try {
      await signInWithSupabase(supabase)
    } catch (error) {
      if (!isCancelledError(error)) {
        Alert.alert('Sign in failed', error instanceof Error ? error.message : 'Unknown error')
      }
    } finally {
      setIsSigningIn(false)
    }
  }

  return <AppleButton onPress={handlePress} disabled={isSigningIn} />
}

Custom label and content ​

label changes only the text. Keep the official wording unless you have a reason to change it.

CustomLabelButton.tsx
tsx
import { AppleButton } from 'expo-apple-sign-in'
import type { ReactElement } from 'react'

export function CustomLabelButton(): ReactElement {
  return <AppleButton buttonStyle="whiteOutline" label="Join with Apple" />
}

children replaces the mark and the label completely. The button keeps its shape, press handling, and accessibility role, but it no longer shows its own spinner, and the accessibility label is still the one for buttonType unless you set label or accessibilityLabel. Use it for layouts the props cannot express. When the appearance is far from the default, a custom control built on the useAppleAuth hook gives you more control.

CustomContentButton.tsx
tsx
import { AppleButton, AppleLogo } from 'expo-apple-sign-in'
import type { ReactElement } from 'react'
import { Text, View } from 'react-native'

export function CustomContentButton(): ReactElement {
  return (
    <AppleButton buttonStyle="white" label="Use my Apple Account">
      <View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>
        <AppleLogo color="#000000" size={20} />
        <Text style={{ color: '#000000', fontWeight: '600' }}>Use my Apple Account</Text>
      </View>
    </AppleButton>
  )
}

AppleLogo renders the Apple mark on its own. It takes a required color, an optional size (default 18), and an optional style for the image on native platforms. On web it draws an inline SVG, and on iOS and Android it draws a tinted image, so the mark is the same shape everywhere.

What the defaults follow ​

The defaults come from the Human Interface Guidelines buttons for Sign in with Apple, and each point below maps to a value in the component:

  • The three label strings are fixed per buttonType and match the official wording.
  • The black, white, and white-with-outline palettes use pure black and white, with the mark and text in the opposite color.
  • The mark is sized to 38% of the button height, and the label is set in semibold weight at 17 points, or 19 points when the height is 52 or more.
  • The label stays on one line and the mark always sits to its left, with an 8-point gap.
  • The corner radius is 8 and the height is 48 unless you change them.

Apple publishes the full rules in the Sign in with Apple HIG. Check them before you override the style, size, or label.

Released under the MIT License.