# Sign in screen

> A complete sign-in screen: email and password, forgot password, an async Sign in button that gathers into a spinner and opens into a check, or shakes together with the password field when the credentials are rejected, and Continue with Apple or Google.

- Type: Component (screens)
- Access: Pro
- Page: https://goodui.dev/native/components/sign-in-screen
- Markdown: https://goodui.dev/native/components/sign-in-screen.md
- Registry item: https://goodui.dev/native/r/sign-in-screen.json
- Dependencies: react-native-svg
- Keywords: react native login screen, expo sign in screen, email password login, sign in with apple google buttons, auth screen template, keyboard aware login form

## When to use

- The sign-in route of an app with email and password accounts, optionally with Apple and Google.
- When you want validation, pending, success and error handled for you: return your auth promise from onSignIn.

## When not to use

- Creating an account: use sign-up-screen, which adds a name, a password strength meter and terms.
- Passwordless email or SMS codes: send the code yourself and use verify-screen.
- A sign-in form inside a sheet over other content: compose text-field and button in bottom-sheet instead.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add @goodui-native-pro/sign-in-screen
npx expo install --fix
```

Pro: add `"@goodui-native-pro": { "url": "https://goodui.dev/native/r/pro/{name}.json", "headers": { "Authorization": "Bearer ${GOODUI_LICENSE_KEY}" } }` to the `registries` of components.json and put your license key in .env.local.

The component lands in `components/goodui-native/sign-in-screen/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs button, icon-button, locale, text-field.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
// app/(auth)/sign-in.tsx
import { router } from "expo-router";
import { SignInScreen } from "@/components/goodui-native/sign-in-screen/sign-in-screen";
import { auth } from "@/lib/auth";

export default function SignInRoute() {
  return (
    <SignInScreen
      appName="Stride"
      onSignIn={({ email, password }) => auth.signInWithPassword(email, password)}
      onSignedIn={() => router.replace("/")}
      onSocialSignIn={(provider) => auth.signInWithProvider(provider)}
      onForgotPassword={(email) => router.push({ pathname: "/reset-password", params: { email } })}
      onCreateAccount={() => router.push("/sign-up")}
      onBack={router.canGoBack() ? router.back : undefined}
    />
  );
}
```

## Examples

### Email only, prefilled

```tsx
<SignInScreen providers={[]} defaultEmail={lastEmail} onSignIn={signIn} onSignedIn={goHome} />
```

### A person-facing error

```tsx
onSignIn={async ({ email, password }) => {
  const { error } = await supabase.auth.signInWithPassword({ email, password });
  if (error) throw new Error("That email and password don't match.");
}}
```

## API reference

### SignInScreen

`import { SignInScreen } from "@/components/goodui-native/sign-in-screen/sign-in-screen";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `appName` | `string` | `"Stride"` | Product name used in the copy ("New to Stride?"). |
| `title` | `string` | `"Welcome back"` | Headline. Sentence case. |
| `subtitle` | `string` | `"Sign in to pick up your training plan where you left it."` | One line under the headline. |
| `logo` | `ReactNode \| null` | – | Mark above the headline, about 56 pt. Defaults to a soft accent tile with a simple glyph; `null` hides it. |
| `defaultEmail` | `string` | `""` | Email to prefill, for example the last account used on this device. |
| `onSignIn` | `(credentials: SignInCredentials) => unknown` | – | Runs when Sign in is pressed with a valid email and a password. Return a promise: while it is pending the button gathers into a spinner; resolve to show the check, reject with an `Error` whose message is person-facing ("That password is incorrect.") to shake the button and show the message under the password. |
| `onSignedIn` | `(credentials: SignInCredentials) => void` | – | Called about 700 ms after `onSignIn` resolves, once the check has landed. Navigate away here. |
| `onSocialSignIn` | `(provider: SignInProvider) => unknown` | – | "Continue with Apple / Google". Return a promise and that button shows its own pending, success and error states. |
| `providers` | `SignInProvider[]` | `["apple", "google"]` | Which "Continue with" buttons to show, in order. `[]` hides them and the divider. Default apple, google. |
| `onForgotPassword` | `(email: string) => void` | – | Forgot password link. Receives the email typed so far so the reset screen can prefill it. |
| `onCreateAccount` | `() => void` | – | "Create an account" link in the footer. Hidden when omitted. |
| `onBack` | `() => void` | – | Shows a back button in the top bar. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- The headline is a header. Fields carry their labels; errors are announced by the text fields and stay visible under them.
- Sign in, Continue with Apple and Continue with Google are buttons that report busy and announce their result; the decorative 'or' divider is hidden from screen readers.
- Forgot password and Create an account are links with a 44 pt touch target from hitSlop.
- Email uses the email keyboard, the username content type and email autofill; the password field uses password autofill and a reveal toggle.

## Motion

- Sign in gathers into a spinner while onSignIn is pending, then opens into a drawn check with 'Signed in'.
- A rejected sign-in shakes the button and, at the same moment, the password field shakes as the message slides in under it.
- Missing or malformed fields shake on their own with the reason under them; no request is made.
- Reduced motion: no shakes and no shape change; states crossfade (handled by button and text-field).

## Haptics

- tap on each button press, success when a sign-in resolves, error when it rejects (from button).
- error from a field that fails validation; a rejected sign-in buzzes once from the button, not again from the field.

## Performance

- Plain state for the two fields; every animation runs on the UI thread inside the kit components.
- Keyboard listeners exist only on Android and only while the screen is mounted; iOS uses the ScrollView's automatic keyboard insets.

## Notes for AI

- Return the auth promise from onSignIn. Reject with an Error whose message a person can read; it is shown under the password. Do not add your own loading state or error text.
- Navigate in onSignedIn, not inside onSignIn, so the check is visible before the route changes.
- onSocialSignIn receives 'apple' or 'google' and should return the provider sign-in promise. providers={[]} hides the buttons and the divider.
- Links and the back button render only when their callback is passed: onForgotPassword, onCreateAccount, onBack.
- Render it as the whole route with the header hidden; it handles safe areas and the keyboard itself.

## Related

- [Sign up screen](https://goodui.dev/native/components/sign-up-screen.md): A complete sign-up screen: name, email and a password with a live strength meter whose segments fill and recolor while each rule's check draws itself in, a terms checkbox and an async Create account button.
- [Verify screen](https://goodui.dev/native/components/verify-screen.md): A complete email or SMS code verification screen: OTP cells that shake and clear on a wrong code, a resend button behind a rolling countdown, and a success check that springs in once the code is accepted.
- [Text field](https://goodui.dev/native/components/text-field.md): A text field whose label glides up as you focus it, with helper and error text that slide in, a shake and haptic on error, clear and reveal buttons, a character counter and a multiline mode that grows with its text.
- [Button](https://goodui.dev/native/components/button.md): A press-responsive button with haptics that runs async actions on its own: it gathers into a spinner, then opens into a success or error state.

## Guidance for AI tools

Sign in screen: A complete sign-in screen: email and password, forgot password, an async Sign in button that gathers into a spinner and opens into a check, or shakes together with the password field when the credentials are rejected, and Continue with Apple or Google. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
