← Files Auth0ARCHIVED FILE

skills/auth0/assets/acul/js-templates/login-password.js

4.23 KB · Oct 4, 2026 · 12:32 UTC

↓ Download file

// ACUL JS — login-password screen boilerplate
// SDK: @auth0/auth0-acul-js
// Customize: apply design tokens, adjust layout

import LoginPassword from '@auth0/auth0-acul-js/login-password'

const manager = new LoginPassword()

function renderErrors() {
  if (!manager.transaction.hasErrors) return ''
  const msgs = manager.getErrors().map(e => `<p>${e.message}</p>`).join('')
  return `<div class="acul-error-banner" role="alert">${msgs}</div>`
}

function renderSocialButtons() {
  const connections = manager.transaction.alternateConnections ?? []
  if (!connections.length) return ''

  return `
    <div class="acul-divider">
      <span>${manager.screen.texts?.separatorText ?? 'Or'}</span>
    </div>
    ${connections.map(conn => `
      <button class="acul-social-btn" data-connection="${conn.name}">
        ${conn.iconUrl ? `<img src="${conn.iconUrl}" alt="" width="20" height="20" />` : ''}
        <span>Continue with ${conn.displayName}</span>
      </button>
    `).join('')}
  `
}

function render() {
  const container = document.getElementById('app')
  container.innerHTML = `
    <div class="acul-page-wrapper">
      <div class="acul-card">
        <div class="acul-logo-slot"></div>

        <h1 class="acul-heading">
          ${manager.screen.texts?.title ?? 'Enter your password'}
        </h1>

        ${renderErrors()}

        <form id="login-password-form" novalidate>
          <div class="acul-field">
            <label class="acul-label" for="password">
              ${manager.screen.texts?.passwordLabel ?? 'Password'}
            </label>
            <div class="acul-input-wrapper">
              <input
                id="password"
                class="acul-input"
                type="password"
                name="password"
                autocomplete="current-password"
                required
              />
              <button type="button" id="toggle-password" class="acul-input-toggle">
                Show
              </button>
            </div>
          </div>

          ${manager.screen.isCaptchaAvailable ? `
            <div class="acul-field">
              <label class="acul-label" for="captcha">
                ${manager.screen.texts?.captchaLabel ?? 'Security code'}
              </label>
              <input id="captcha" class="acul-input" type="text" />
            </div>
          ` : ''}

          <button id="submit-btn" type="submit" class="acul-btn-primary">
            ${manager.screen.texts?.buttonText ?? 'Log in'}
          </button>
        </form>

        ${manager.screen.isPasskeyEnabled ? `
          <button id="passkey-btn" class="acul-btn-secondary">
            ${manager.screen.texts?.passkeyButtonText ?? 'Use a passkey instead'}
          </button>
        ` : ''}

        ${renderSocialButtons()}

        <div class="acul-footer-links">
          <a href="#">
            ${manager.screen.texts?.forgotPasswordText ?? 'Forgot password?'}
          </a>
        </div>
      </div>
    </div>
  `

  attachEventListeners()
}

function attachEventListeners() {
  document.getElementById('login-password-form')?.addEventListener('submit', async (e) => {
    e.preventDefault()
    const submitBtn = document.getElementById('submit-btn')
    submitBtn.disabled = true
    submitBtn.textContent = 'Loading...'

    const password = document.getElementById('password').value
    const captcha = document.getElementById('captcha')?.value

    await manager.login({ password, captcha: captcha || undefined })

    submitBtn.disabled = false
    submitBtn.textContent = manager.screen.texts?.buttonText ?? 'Log in'
  })

  document.getElementById('toggle-password')?.addEventListener('click', () => {
    const input = document.getElementById('password')
    const btn = document.getElementById('toggle-password')
    if (input.type === 'password') {
      input.type = 'text'
      btn.textContent = 'Hide'
    } else {
      input.type = 'password'
      btn.textContent = 'Show'
    }
  })

  document.getElementById('passkey-btn')?.addEventListener('click', async () => {
    await manager.passkeyLogin()
  })

  document.querySelectorAll('.acul-social-btn').forEach(btn => {
    btn.addEventListener('click', async () => {
      await manager.federatedLogin({ connection: btn.dataset.connection })
    })
  })
}

render()

SHA-256: 41219fef7df238abe2e6042f14f8d6a2e3f8cfce2a666f27dea6a5142a340802