Skip to content

OAuthButtons (Component)

Description

The OAuthButtons component is a versatile authentication button system designed to handle OAuth providers with consistent styling and behavior. It supports multiple providers including GitHub, Apple, X (Twitter), Google, and a default option with customizable variants and sizes.

Preview

OAuth Buttons Component Variants
*Modern OAuth authentication buttons with provider-specific styling and loading states*

Features

  • 🔐 Multiple OAuth Providers (GitHub, Apple, X, Google, Default)
  • 🎨 Provider-specific styling with brand colors
  • 📱 Responsive design with multiple sizes
  • Loading states with spinner animations
  • 🌙 Dark mode support with automatic theme switching
  • Accessibility with proper ARIA labels
  • 🎯 Customizable text and click handlers

Usage

Import

vue
<template>
  <OAuthButtons 
    provider="github"
    variant="primary"
    size="md"
    @click="handleAuth"
  />
</template>

Props

PropTypeDefaultDescription
provider'github' | 'apple' | 'x' | 'google' | 'default''default'OAuth provider type
variant'primary' | 'secondary' | 'outline''primary'Button style variant
size'sm' | 'md' | 'lg''md'Button size
disabledbooleanfalseDisable button interaction
loadingbooleanfalseShow loading spinner
textstring''Custom button text
onClick() => voidundefinedClick handler function

Examples

Basic Usage

vue
<template>
  <OAuthButtons provider="github" />
</template>

Multiple Providers

vue
<template>
  <div class="space-y-3">
    <OAuthButtons 
      provider="github" 
      @click="handleGitHubAuth"
    />
    <OAuthButtons 
      provider="google" 
      @click="handleGoogleAuth"
    />
    <OAuthButtons 
      provider="apple" 
      @click="handleAppleAuth"
    />
    <OAuthButtons 
      provider="x" 
      @click="handleXAuth"
    />
  </div>
</template>

<script setup>
const handleGitHubAuth = () => {
  // GitHub OAuth logic
  console.log('GitHub authentication')
}

const handleGoogleAuth = () => {
  // Google OAuth logic
  console.log('Google authentication')
}

const handleAppleAuth = () => {
  // Apple OAuth logic
  console.log('Apple authentication')
}

const handleXAuth = () => {
  // X (Twitter) OAuth logic
  console.log('X authentication')
}
</script>

With Loading States

vue
<template>
  <div class="space-y-3">
    <OAuthButtons 
      provider="github" 
      :loading="isGitHubLoading"
      @click="handleGitHubAuth"
    />
    <OAuthButtons 
      provider="google" 
      :loading="isGoogleLoading"
      @click="handleGoogleAuth"
    />
  </div>
</template>

<script setup>
const isGitHubLoading = ref(false)
const isGoogleLoading = ref(false)

const handleGitHubAuth = async () => {
  isGitHubLoading.value = true
  try {
    // GitHub OAuth logic
    await authenticateWithGitHub()
  } finally {
    isGitHubLoading.value = false
  }
}

const handleGoogleAuth = async () => {
  isGoogleLoading.value = true
  try {
    // Google OAuth logic
    await authenticateWithGoogle()
  } finally {
    isGoogleLoading.value = false
  }
}
</script>

Different Sizes

vue
<template>
  <div class="space-y-4">
    <div>
      <label class="text-sm font-medium text-gray-700 mb-2 block">Small</label>
      <OAuthButtons provider="github" size="sm" />
    </div>
    
    <div>
      <label class="text-sm font-medium text-gray-700 mb-2 block">Medium</label>
      <OAuthButtons provider="github" size="md" />
    </div>
    
    <div>
      <label class="text-sm font-medium text-gray-700 mb-2 block">Large</label>
      <OAuthButtons provider="github" size="lg" />
    </div>
  </div>
</template>

Custom Text

vue
<template>
  <OAuthButtons 
    provider="github"
    text="Sign in with GitHub"
    @click="handleAuth"
  />
</template>

Disabled State

vue
<template>
  <OAuthButtons 
    provider="github"
    :disabled="true"
    text="Authentication Unavailable"
  />
</template>

Provider Configurations

Each provider has specific styling and branding:

GitHub

  • Icon: logos:github-icon
  • Default Text: "Continue with GitHub"
  • Colors: Dark gray background with white text

Apple

  • Icon: logos:apple
  • Default Text: "Continue with Apple"
  • Colors: Black background with white text

X (Twitter)

  • Icon: logos:x
  • Default Text: "Continue with X"
  • Colors: Black background with white text

Google

  • Icon: logos:google-icon
  • Default Text: "Continue with Google"
  • Colors: White background with gray text and border

Default

  • Icon: lucide:user
  • Default Text: "Continue"
  • Colors: Blue background with white text

Styling and Themes

The component uses Tailwind CSS classes and automatically adapts to light/dark themes:

Base Classes

  • inline-flex items-center justify-center : Flex layout
  • font-medium : Medium font weight
  • transition-all duration-200 : Smooth transitions
  • focus:outline-none focus:ring-2 focus:ring-offset-2 : Focus states
  • disabled:opacity-50 disabled:cursor-not-allowed : Disabled states

Size Classes

  • Small: px-3 py-2 text-sm rounded-md
  • Medium: px-4 py-2 text-sm rounded-lg
  • Large: px-6 py-3 text-base rounded-lg

Provider Colors

Each provider has specific color schemes that work in both light and dark modes.

Loading States

When loading is true:

  • Shows a spinning loader icon (lucide:loader-2)
  • Disables button interaction
  • Updates ARIA label to "Loading..."

Accessibility

  • ARIA Labels: Dynamic labels based on loading state
  • Keyboard Navigation: Full keyboard support
  • Focus Management: Visible focus rings
  • Screen Reader Support: Proper semantic markup

Integration Examples

Supabase Auth Integration

vue
<template>
  <div class="space-y-3">
    <OAuthButtons 
      provider="github" 
      :loading="isLoading"
      @click="signInWithGitHub"
    />
    <OAuthButtons 
      provider="google" 
      :loading="isLoading"
      @click="signInWithGoogle"
    />
  </div>
</template>

<script setup>
const supabase = useSupabaseClient()
const isLoading = ref(false)

const signInWithGitHub = async () => {
  isLoading.value = true
  try {
    const { error } = await supabase.auth.signInWithOAuth({
      provider: 'github',
      options: {
        redirectTo: `${window.location.origin}/auth/callback`
      }
    })
    if (error) throw error
  } catch (error) {
    console.error('GitHub auth error:', error)
  } finally {
    isLoading.value = false
  }
}

const signInWithGoogle = async () => {
  isLoading.value = true
  try {
    const { error } = await supabase.auth.signInWithOAuth({
      provider: 'google',
      options: {
        redirectTo: `${window.location.origin}/auth/callback`
      }
    })
    if (error) throw error
  } catch (error) {
    console.error('Google auth error:', error)
  } finally {
    isLoading.value = false
  }
}
</script>

Custom OAuth Flow

vue
<template>
  <OAuthButtons 
    provider="github"
    :loading="isLoading"
    @click="handleCustomAuth"
  />
</template>

<script setup>
const isLoading = ref(false)

const handleCustomAuth = async () => {
  isLoading.value = true
  try {
    // Custom OAuth implementation
    const response = await fetch('/api/auth/github', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      }
    })
    
    if (response.ok) {
      const data = await response.json()
      // Handle successful authentication
      await navigateTo('/dashboard')
    } else {
      throw new Error('Authentication failed')
    }
  } catch (error) {
    console.error('Authentication error:', error)
    // Show error message to user
  } finally {
    isLoading.value = false
  }
}
</script>

Best Practices

  1. Always handle loading states to provide user feedback
  2. Use appropriate provider icons for brand consistency
  3. Implement proper error handling for OAuth flows
  4. Test accessibility with keyboard navigation
  5. Provide fallback options for unsupported providers
  6. Use consistent sizing across your authentication flow

Troubleshooting

Button doesn't respond to clicks

  • Check that the @click event is properly attached
  • Ensure the button is not disabled or in loading state
  • Verify the onClick prop function is defined

Icons don't display

  • Verify that the Iconify library is properly configured
  • Check that the icon names are correct
  • Ensure the icon library is loaded

Styling issues

  • Verify Tailwind CSS is configured
  • Check for CSS conflicts with other styles
  • Ensure dark mode classes are working

OAuth flow not working

  • Verify OAuth provider configuration
  • Check redirect URLs are properly set
  • Ensure API keys and secrets are configured

Complete Example

vue
<template>
  <div class="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
    <div class="max-w-md w-full space-y-8">
      <div>
        <h2 class="mt-6 text-center text-3xl font-extrabold text-gray-900 dark:text-white">
          Sign in to your account
        </h2>
        <p class="mt-2 text-center text-sm text-gray-600 dark:text-gray-400">
          Choose your preferred authentication method
        </p>
      </div>
      
      <div class="space-y-4">
        <OAuthButtons 
          provider="github" 
          size="lg"
          :loading="isGitHubLoading"
          @click="signInWithGitHub"
        />
        
        <OAuthButtons 
          provider="google" 
          size="lg"
          :loading="isGoogleLoading"
          @click="signInWithGoogle"
        />
        
        <OAuthButtons 
          provider="apple" 
          size="lg"
          :loading="isAppleLoading"
          @click="signInWithApple"
        />
        
        <OAuthButtons 
          provider="x" 
          size="lg"
          :loading="isXLoading"
          @click="signInWithX"
        />
      </div>
      
      <div class="text-center">
        <p class="text-sm text-gray-600 dark:text-gray-400">
          By continuing, you agree to our Terms of Service and Privacy Policy
        </p>
      </div>
    </div>
  </div>
</template>

<script setup>
const supabase = useSupabaseClient()
const isLoading = ref(false)

const isGitHubLoading = ref(false)
const isGoogleLoading = ref(false)
const isAppleLoading = ref(false)
const isXLoading = ref(false)

const signInWithProvider = async (provider: string) => {
  const loadingRef = {
    github: isGitHubLoading,
    google: isGoogleLoading,
    apple: isAppleLoading,
    x: isXLoading
  }[provider]
  
  if (loadingRef) {
    loadingRef.value = true
  }
  
  try {
    const { error } = await supabase.auth.signInWithOAuth({
      provider: provider as any,
      options: {
        redirectTo: `${window.location.origin}/auth/callback`
      }
    })
    
    if (error) throw error
  } catch (error) {
    console.error(`${provider} auth error:`, error)
    // Show error toast or notification
  } finally {
    if (loadingRef) {
      loadingRef.value = false
    }
  }
}

const signInWithGitHub = () => signInWithProvider('github')
const signInWithGoogle = () => signInWithProvider('google')
const signInWithApple = () => signInWithProvider('apple')
const signInWithX = () => signInWithProvider('x')
</script>

This component is part of the ClawPlate suite and is optimized for modern SaaS applications with OAuth authentication.

Built with love by mhdevfr