← Components/Authentication

MagicLinkAuth

magiclinkauth-1779378413124.tsx
'use client'
import { useState } from 'react'

type State = 'idle' | 'sending' | 'sent' | 'error'

export default function MagicLinkAuth() {
  const [email, setEmail] = useState('')
  const [state, setState] = useState<State>('idle')

  async function send() {
    if (!email.includes('@')) return
    setState('sending')
    await new Promise(r => setTimeout(r, 1500))
    setState('sent')
  }

  if (state === 'sent') {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 60, background: '#0A0A0A' }}>
        <div style={{ textAlign: 'center', maxWidth: 360 }}>
          <div style={{ fontSize: 64, marginBottom: 20, animation: 'bounce 1s ease' }}>📬</div>
          <h2 style={{ color: '#F5F5F0', fontSize: 22, fontWeight: 700, marginBottom: 12 }}>Check your inbox</h2>
          <p style={{ color: '#666', lineHeight: 1.6, marginBottom: 24 }}>
            We sent a magic link to <strong style={{ color: '#C9A84C' }}>{email}</strong>. Click it to sign in — valid for 15 minutes.
          </p>
          <button onClick={() => { setState('idle'); setEmail('') }} style={{
            background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)',
            color: '#aaa', padding: '10px 20px', borderRadius: 8, cursor: 'pointer', fontSize: 14,
          }}>Use a different email</button>
        </div>
      </div>
    )
  }

  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 60, background: '#0A0A0A' }}>
      <div style={{ width: '100%', maxWidth: 380 }}>
        <div style={{ textAlign: 'center', marginBottom: 32 }}>
          <div style={{ color: '#C9A84C', fontWeight: 800, fontSize: 22, marginBottom: 8 }}>EMPIRE UI</div>
          <h2 style={{ color: '#F5F5F0', fontSize: 22, fontWeight: 700 }}>Sign in with email</h2>
          <p style={{ color: '#666', fontSize: 14, marginTop: 4 }}>No password. Just a magic link.</p>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <input
            type="email" value={email} onChange={e => setEmail(e.target.value)}
            placeholder="you@company.com"
            onKeyDown={e => e.key === 'Enter' && send()}
            style={{
              background: '#111', border: '1px solid rgba(255,255,255,0.1)',
              color: '#F5F5F0', padding: '14px 16px', borderRadius: 10,
              fontSize: 15, outline: 'none', width: '100%', boxSizing: 'border-box',
            }}
          />
          <button onClick={send} disabled={state === 'sending' || !email.includes('@')} style={{
            background: state === 'sending' ? 'rgba(201,168,76,0.5)' : email.includes('@') ? '#C9A84C' : 'rgba(255,255,255,0.06)',
            border: 'none', color: email.includes('@') ? '#0A0A0A' : '#555',
            padding: '14px', borderRadius: 10, cursor: email.includes('@') ? 'pointer' : 'not-allowed',
            fontWeight: 700, fontSize: 15, transition: 'all 0.2s',
          }}>
            {state === 'sending' ? '⏳ Sending...' : 'Send magic link ✨'}
          </button>
        </div>

        <div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '20px 0' }}>
          <div style={{ flex: 1, height: 1, background: 'rgba(255,255,255,0.06)' }} />
          <span style={{ color: '#444', fontSize: 13 }}>or</span>
          <div style={{ flex: 1, height: 1, background: 'rgba(255,255,255,0.06)' }} />
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          {[{ icon: '🐙', label: 'Continue with GitHub' }, { icon: '🔵', label: 'Continue with Google' }].map(p => (
            <button key={p.label} style={{
              background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.08)',
              color: '#F5F5F0', padding: '13px', borderRadius: 10, cursor: 'pointer',
              fontSize: 14, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10,
            }}>{p.icon} {p.label}</button>
          ))}
        </div>

        <p style={{ textAlign: 'center', color: '#444', fontSize: 12, marginTop: 20, lineHeight: 1.5 }}>
          By signing in you agree to our Terms of Service and Privacy Policy.
        </p>
      </div>
    </div>
  )
}

Component info

CategoryAuthentication
Frameworkreact
TierFREE
Views0
Copies0

About

Magic link email authentication with animated send state and success confirmation

More from Authentication

'use client'
import { useState } from 'react'

export default function LoginForm() {
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [showPw, setShowPw] = useState(false)
  const [remember, setRemember]
LoginForm
Authentication
'use client';

import React, { useState } from 'react';

interface LoginFormProps {
  onSubmit: (email: string, password: string) => void;
}

const LoginForm: React.FC<LoginFormProps> = ({ onSubmit }) => {
  const [email, setEmail] = useState('');
  
LoginForm
Authentication
'use client';

import { useState } from 'react';

interface SignupFormProps {
  // No props for this component
}

const SignupForm: React.FC<SignupFormProps> = () => {
  const [step, setStep] = useState(1);
  const [email, setEmail] = useState('');
 
SignupForm
Authentication
'use client';

import React, { useState } from 'react';

interface ForgotPasswordProps {
  // No props needed for this component
}

const ForgotPassword: React.FC<ForgotPasswordProps> = () => {
  const [email, setEmail] = useState('');
  const [isSub
ForgotPassword
Authentication