|
| 1 | +# SignInButton |
| 2 | + |
| 3 | +The `SignInButton` component provides a pre-built, customizable button that handles user authentication through the Asgardeo identity provider. It supports both render props and traditional props patterns, making it flexible for various UI implementations. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The `SignInButton` component automatically integrates with the Asgardeo authentication context and handles the sign-in flow including loading states, error handling, and redirection. It leverages the `useAsgardeo` hook to access authentication methods and can be customized with preferences for internationalization and theming. |
| 8 | + |
| 9 | +## Basic Usage |
| 10 | + |
| 11 | +### Traditional Props Pattern |
| 12 | + |
| 13 | +```tsx |
| 14 | +import React from 'react'; |
| 15 | +import { SignInButton } from '@asgardeo/react'; |
| 16 | + |
| 17 | +function LoginPage() { |
| 18 | + return ( |
| 19 | + <div> |
| 20 | + <h1>Welcome to Our App</h1> |
| 21 | + <SignInButton>Sign In</SignInButton> |
| 22 | + </div> |
| 23 | + ); |
| 24 | +} |
| 25 | +``` |
| 26 | + |
| 27 | +### With Custom Styling |
| 28 | + |
| 29 | +```tsx |
| 30 | +import React from 'react'; |
| 31 | +import { SignInButton } from '@asgardeo/react'; |
| 32 | + |
| 33 | +function CustomLoginPage() { |
| 34 | + return ( |
| 35 | + <SignInButton |
| 36 | + className="bg-blue-500 text-white px-6 py-3 rounded-lg hover:bg-blue-600" |
| 37 | + style={{ fontSize: '16px', fontWeight: 'bold' }} |
| 38 | + > |
| 39 | + Get Started |
| 40 | + </SignInButton> |
| 41 | + ); |
| 42 | +} |
| 43 | +``` |
| 44 | + |
| 45 | +## Advanced Usage |
| 46 | + |
| 47 | +### Render Props Pattern |
| 48 | + |
| 49 | +The render props pattern gives you full control over the button's appearance and behavior while still leveraging the authentication logic: |
| 50 | + |
| 51 | +```tsx |
| 52 | +import React from 'react'; |
| 53 | +import { SignInButton } from '@asgardeo/react'; |
| 54 | + |
| 55 | +function AdvancedLoginPage() { |
| 56 | + return ( |
| 57 | + <SignInButton> |
| 58 | + {({ signIn, isLoading }) => ( |
| 59 | + <button |
| 60 | + onClick={signIn} |
| 61 | + disabled={isLoading} |
| 62 | + className="custom-auth-button" |
| 63 | + > |
| 64 | + {isLoading ? ( |
| 65 | + <> |
| 66 | + <LoadingSpinner /> |
| 67 | + Signing in... |
| 68 | + </> |
| 69 | + ) : ( |
| 70 | + <> |
| 71 | + <LoginIcon /> |
| 72 | + Sign In with Asgardeo |
| 73 | + </> |
| 74 | + )} |
| 75 | + </button> |
| 76 | + )} |
| 77 | + </SignInButton> |
| 78 | + ); |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +### Custom Click Handler |
| 83 | + |
| 84 | +```tsx |
| 85 | +import React from 'react'; |
| 86 | +import { SignInButton } from '@asgardeo/react'; |
| 87 | + |
| 88 | +function TrackingLoginPage() { |
| 89 | + const handleSignInClick = (event) => { |
| 90 | + // Track analytics event |
| 91 | + analytics.track('sign_in_button_clicked'); |
| 92 | + console.log('User initiated sign-in process'); |
| 93 | + }; |
| 94 | + |
| 95 | + return ( |
| 96 | + <SignInButton onClick={handleSignInClick}> |
| 97 | + Sign In |
| 98 | + </SignInButton> |
| 99 | + ); |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +### Component-Level Internationalization |
| 104 | + |
| 105 | +```tsx |
| 106 | +import React from 'react'; |
| 107 | +import { SignInButton } from '@asgardeo/react'; |
| 108 | + |
| 109 | +function LocalizedLoginPage() { |
| 110 | + return ( |
| 111 | + <SignInButton |
| 112 | + preferences={{ |
| 113 | + i18n: { |
| 114 | + bundles: { |
| 115 | + 'es-ES': { |
| 116 | + translations: { |
| 117 | + 'elements.buttons.signIn': 'Iniciar Sesión' |
| 118 | + } |
| 119 | + }, |
| 120 | + 'fr-FR': { |
| 121 | + translations: { |
| 122 | + 'elements.buttons.signIn': 'Se Connecter' |
| 123 | + } |
| 124 | + } |
| 125 | + } |
| 126 | + } |
| 127 | + }} |
| 128 | + > |
| 129 | + {/* Will use localized text from preferences */} |
| 130 | + </SignInButton> |
| 131 | + ); |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | +## Props |
| 136 | + |
| 137 | +The `SignInButton` component accepts all standard HTML button attributes plus the following: |
| 138 | + |
| 139 | +### SignInButtonProps |
| 140 | + |
| 141 | +| Prop | Type | Default | Description | |
| 142 | +|------|------|---------|-------------| |
| 143 | +| `children` | `ReactNode \| ((props: RenderProps) => ReactNode)` | Localized "Sign In" text | Button content or render function | |
| 144 | +| `onClick` | `(event: MouseEvent<HTMLButtonElement>) => void` | - | Custom click handler called after sign-in initiation | |
| 145 | +| `className` | `string` | - | Additional CSS classes to apply to the button | |
| 146 | +| `style` | `CSSProperties` | - | Inline styles to apply to the button | |
| 147 | +| `preferences` | `Preferences` | - | Component-level configuration for theming and internationalization | |
| 148 | +| `disabled` | `boolean` | `false` | Whether the button is disabled (overridden during loading) | |
| 149 | +| `type` | `"button" \| "submit" \| "reset"` | `"button"` | HTML button type | |
| 150 | + |
| 151 | +### Render Props |
| 152 | + |
| 153 | +When using the render props pattern, the function receives the following props: |
| 154 | + |
| 155 | +| Prop | Type | Description | |
| 156 | +|------|------|-------------| |
| 157 | +| `signIn` | `() => Promise<void>` | Function to initiate the sign-in process | |
| 158 | +| `isLoading` | `boolean` | Whether the sign-in process is currently in progress | |
| 159 | + |
| 160 | +## Preferences |
| 161 | + |
| 162 | +The `preferences` prop allows you to customize the component's behavior and appearance. |
| 163 | + |
| 164 | +| Property | Type | Default | Description | |
| 165 | +|----------|------|---------|-------------| |
| 166 | +| `i18n` | `I18nConfig` | - | Internationalization configuration for custom translations | |
| 167 | +| `theme` | `ThemeConfig` | - | Theme configuration for styling customization | |
| 168 | + |
| 169 | +### I18nConfig |
| 170 | + |
| 171 | +| Property | Type | Description | |
| 172 | +|----------|------|-------------| |
| 173 | +| `bundles` | `Record<string, { translations: Record<string, string> }>` | Translation bundles keyed by locale | |
| 174 | + |
| 175 | +For the SignInButton, the relevant translation key is: |
| 176 | + |
| 177 | +- `elements.buttons.signIn` - The default button text |
| 178 | + |
| 179 | + |
| 180 | +## Behavior |
| 181 | + |
| 182 | +### Authentication Flow |
| 183 | + |
| 184 | +1. **Initial State**: Button displays with default or custom text |
| 185 | +2. **Click Event**: User clicks the button, triggering the sign-in process |
| 186 | +3. **Loading State**: Button becomes disabled and shows loading indicator |
| 187 | +4. **Navigation**: User is redirected to Asgardeo sign-in page or custom sign-in URL |
| 188 | +5. **Completion**: After successful authentication, user returns to the application |
| 189 | + |
| 190 | +### Custom Sign-In URL |
| 191 | + |
| 192 | +If a `signInUrl` is configured in the `AsgardeoProvider`, the button will navigate to that URL instead of initiating the OAuth flow directly: |
| 193 | + |
| 194 | +```tsx |
| 195 | +// In your AsgardeoProvider configuration |
| 196 | +<AsgardeoProvider |
| 197 | + signInUrl="/custom-login" |
| 198 | + // ... other props |
| 199 | +> |
| 200 | + <App /> |
| 201 | +</AsgardeoProvider> |
| 202 | +``` |
| 203 | + |
| 204 | +### Error Handling |
| 205 | + |
| 206 | +The component automatically handles sign-in errors and throws an `AsgardeoRuntimeError` with detailed information: |
| 207 | + |
| 208 | +```tsx |
| 209 | +// Error details include: |
| 210 | +// - Error message |
| 211 | +// - Error code: 'SignInButton-handleSignIn-RuntimeError-001' |
| 212 | +// - Package: 'react' |
| 213 | +// - User-friendly message |
| 214 | +``` |
| 215 | + |
| 216 | +## Accessibility |
| 217 | + |
| 218 | +The `SignInButton` component includes accessibility features: |
| 219 | + |
| 220 | +- **Keyboard Navigation**: Fully keyboard accessible |
| 221 | +- **Screen Readers**: Proper ARIA attributes and semantic HTML |
| 222 | +- **Loading States**: Disabled state prevents multiple submissions |
| 223 | +- **Focus Management**: Maintains focus states for keyboard users |
| 224 | + |
| 225 | +## Integration with BaseSignInButton |
| 226 | + |
| 227 | +The `SignInButton` is built on top of `BaseSignInButton`, which provides the core functionality. If you need more control or want to build a custom implementation, you can use `BaseSignInButton` directly: |
| 228 | + |
| 229 | +```tsx |
| 230 | +import React, { useState } from 'react'; |
| 231 | +import { BaseSignInButton } from '@asgardeo/react'; |
| 232 | +import { useAsgardeo } from '@asgardeo/react'; |
| 233 | + |
| 234 | +function CustomSignInButton() { |
| 235 | + const { signIn } = useAsgardeo(); |
| 236 | + const [isLoading, setIsLoading] = useState(false); |
| 237 | + |
| 238 | + const handleSignIn = async () => { |
| 239 | + setIsLoading(true); |
| 240 | + try { |
| 241 | + await signIn(); |
| 242 | + } finally { |
| 243 | + setIsLoading(false); |
| 244 | + } |
| 245 | + }; |
| 246 | + |
| 247 | + return ( |
| 248 | + <BaseSignInButton |
| 249 | + signIn={handleSignIn} |
| 250 | + isLoading={isLoading} |
| 251 | + > |
| 252 | + Custom Sign In Implementation |
| 253 | + </BaseSignInButton> |
| 254 | + ); |
| 255 | +} |
| 256 | +``` |
| 257 | + |
| 258 | +## Best Practices |
| 259 | + |
| 260 | +### 1. Consistent Styling |
| 261 | + |
| 262 | +Maintain consistent button styling across your application: |
| 263 | + |
| 264 | +```tsx |
| 265 | +// Create a styled wrapper |
| 266 | +const StyledSignInButton = styled(SignInButton)` |
| 267 | + background: var(--primary-color); |
| 268 | + color: white; |
| 269 | + border-radius: 8px; |
| 270 | + padding: 12px 24px; |
| 271 | + font-weight: 600; |
| 272 | + |
| 273 | + &:hover { |
| 274 | + background: var(--primary-hover-color); |
| 275 | + } |
| 276 | +`; |
| 277 | +``` |
| 278 | + |
| 279 | +### 2. Loading States |
| 280 | + |
| 281 | +Always provide clear feedback during the sign-in process: |
| 282 | + |
| 283 | +```tsx |
| 284 | +<SignInButton> |
| 285 | + {({ isLoading }) => ( |
| 286 | + <> |
| 287 | + {isLoading && <LoadingSpinner />} |
| 288 | + {isLoading ? 'Signing in...' : 'Sign In'} |
| 289 | + </> |
| 290 | + )} |
| 291 | +</SignInButton> |
| 292 | +``` |
| 293 | + |
| 294 | +### 3. Error Boundaries |
| 295 | + |
| 296 | +Wrap your authentication components in error boundaries to handle potential errors gracefully: |
| 297 | + |
| 298 | +```tsx |
| 299 | +<ErrorBoundary fallback={<div>Something went wrong</div>}> |
| 300 | + <SignInButton>Sign In</SignInButton> |
| 301 | +</ErrorBoundary> |
| 302 | +``` |
| 303 | + |
| 304 | +### 4. Responsive Design |
| 305 | + |
| 306 | +Ensure your sign-in button works well on all device sizes: |
| 307 | + |
| 308 | +```tsx |
| 309 | +<SignInButton className="w-full md:w-auto px-4 py-2 text-sm md:text-base"> |
| 310 | + Sign In |
| 311 | +</SignInButton> |
| 312 | +``` |
| 313 | + |
| 314 | +## Common Issues |
| 315 | + |
| 316 | +### Button Not Working |
| 317 | + |
| 318 | +- Ensure `AsgardeoProvider` is properly configured and wrapping your component |
| 319 | +- Check that all required configuration props are provided |
| 320 | +- Verify network connectivity and Asgardeo service availability |
| 321 | + |
| 322 | +### Custom Styling Not Applied |
| 323 | + |
| 324 | +- Check CSS specificity and ensure your styles are not being overridden |
| 325 | +- Use browser developer tools to inspect the rendered element |
| 326 | +- Consider using CSS-in-JS solutions or CSS modules for better style isolation |
| 327 | + |
| 328 | +### Translation Not Showing |
| 329 | + |
| 330 | +- Verify the translation key `elements.buttons.signIn` exists in your bundles |
| 331 | +- Check that the locale is correctly set in your preferences |
| 332 | +- Ensure the `preferences` prop is passed correctly |
| 333 | + |
| 334 | +## Related Components |
| 335 | + |
| 336 | +- [`AsgardeoProvider`](./asgardeo-provider.md) - Required context provider for authentication |
| 337 | +- [`BaseSignInButton`](#integration-with-basesigninbutton) - Lower-level component for custom implementations |
| 338 | +- [`SignOutButton`](./sign-out-button.md) - Companion component for signing out users |
0 commit comments