Skip to main content

LoginForm

<allegro-login-form> is a web component that authenticates readers via a magic login link sent to their email, a six-digit one-time code, or via Google, Apple, or Facebook OAuth. The email-based method is chosen with the login-method attribute — magic link by default. The email input and submit button always stack vertically; social login buttons sit side by side when the form is wide enough to give each at least 12.5rem, and stack otherwise.

See every state of <allegro-login-form> in Storybook.

Set login-method="magic-link-otp" to send a single email containing both a magic link and a six-digit code. The form has one submit button, just like the single-method layouts; submitting it emails the reader both options and shows the code-entry screen. Clicking the link in the email authenticates directly (the form polls for that in the background), or the reader can type the code instead — whichever they do first signs them in.

Usage​

<allegro-login-form></allegro-login-form>

Customize the text labels via HTML attributes:

<allegro-login-form
form-label-text="Your email"
show-form-label="false"
placeholder-text="Your email"
button-text="Get my link"
publisher-name="Example News"
continue-text="Keep Reading"
hide-third-party="true"
></allegro-login-form>

Send a magic link and a one-time code together from a single form:

<allegro-login-form
login-method="magic-link-otp"
button-text="Sign in securely"
></allegro-login-form>

Attributes​

AttributeTypeDefaultDescription
headingtext(empty)Heading shown above the email field in the email state. Style it with the heading part or the heading variables.
descriptiontext(empty)Short text shown under the heading in the email state.
show-form-labelbooleantrueWhether to show the email field's label. When false, the label is still rendered for screen readers but visually hidden. If placeholder-text is empty, the label text is used as the placeholder so the field still has visible text.
form-label-texttextEmail AddressLabel text for the email input field.
placeholder-texttextEnter your emailPlaceholder shown inside the email input.
emailtext(empty)Email address to prefill in the email input. The reader can still change it.
button-texttextSign inLabel for the submit button in every login method. Defaults to Continue when registration-form is set.
login-methodtextmagic-linkAuthentication method: magic-link (emails a login link), otp (emails a 6-digit code), or magic-link-otp (emails both a link and a code).
registration-formtext(empty)Slug of a form whose fields a new reader fills in before their account is created. See Registration fields.
register-button-texttextCreate accountLabel for the submit button once registration fields are showing.
registration-texttextTell us a bit about yourself to create your account.Text shown above the registration fields and announced to screen readers when they appear. Set it to an empty value to hide it; screen readers still hear the default message.
hide-third-partybooleanfalseSet to true to hide all social login buttons (Google, Apple, Facebook).
publisher-nametext(empty)Publisher name shown in the success state, e.g. "Welcome back to Example News!"
continue-texttext(empty)Override the continue button label in the success state.
learn-more-urltext(empty)http or https URL to navigate to when the continue button is clicked in success state. Other URLs are ignored.
show-last-usedbooleanfalseSet to true to show a "Last used" badge on the login method (social provider or email) the reader most recently used to sign in. Recorded per-browser in localStorage. See Last used badge.
suppress-successbooleanfalseSkip the built-in success screen after authentication. The authentication events still fire.
tracking-datatext(empty)JSON object of custom data merged into the events the component tracks itself, e.g. "{'campaign': 'header'}". Events the SDK records during sign-in (magic_link_requested, otp_requested, magic_link_otp_requested, otp_validated) do not include it.

Captcha​

When the organization — or the property serving the page — has a captcha provider configured in Organization Settings › Access & Identity › Captcha, this component loads it and verifies every sign-in request automatically. Your markup does not change: the provider's script is fetched on demand and the resulting token is attached to the request.

Google reCAPTCHA v3 is invisible, so readers are scored in the background and never see a challenge. Google appends its own floating badge to the page, which its branding terms require you to keep or replace with the prescribed attribution text near your submit button.

There is no per-element opt-out. A form that could switch the check off from the page would let any caller do the same, so captcha is controlled entirely in organization settings. When no provider is configured, the component behaves exactly as it did before — no extra script, no extra request.

Failure modes worth handling​

A request whose token is missing or scores below the organization's threshold is rejected before any email is sent:

{ "data": { "code": "CAPTCHA_FAILED", "message": "…" }, "status": 422 }

That surfaces through the SDK's usual AllegroApiError path, so an allegro:login-form:error listener sees it like any other failure. The component already renders the message inline; you only need to handle it if you have replaced the default error display.

If the provider itself is unreachable, the request is allowed through rather than rejected, so a Google outage cannot lock readers out.

A reader whose browser blocks Google's script is rejected, since a client able to skip the check by reporting failure would make it decorative. The script loader does not cache a failed load, so pressing the button again genuinely retries rather than replaying the failure.

Content Security Policy​

Loading the provider adds a script origin. A publisher with a strict CSP needs:

script-src https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/;
frame-src https://www.google.com/recaptcha/;

Without these the script is blocked silently and sign-in fails for every reader on that page while captcha is switched on.

note

Alpine-driven interactions already load from https://cdn.jsdelivr.net, which a strict script-src must also allow. That requirement predates captcha and is easy to miss when auditing a policy.

Last used badge​

Set show-last-used to display a small "Last used" badge over the login method the reader most recently used, helping returning readers pick the same method again:

<allegro-login-form show-last-used></allegro-login-form>

The last-used method is recorded in the browser's localStorage (key allegro:login-form:last-used) at the moment the reader initiates a login — clicking a social provider button or submitting the email form. Recording only happens when show-last-used is set, and the badge appears on the reader's next visit. Because it is stored per browser, the badge does not follow the reader across devices. If the last-used social provider is later disabled for the tenant, no badge is shown.

Style the badge with the last-used-badge shadow part and the --loginForm--last-used--* CSS variables listed below.

Registration fields​

Set registration-form to the slug of a form built under Forms to ask new readers a few questions, like their name, as part of creating their account.

<allegro-login-form registration-form="signup"></allegro-login-form>
  1. The reader enters their email and presses Continue. While the email is checked, a spinner shows inside the field.
  2. If the email belongs to an existing account, the login email goes out as usual and nothing else changes.
  3. If the email is new, no email is sent yet. The form's fields open below the email field, focus moves to the first one, and the button changes to Create account.
  4. When the reader submits, the answers are validated against the form's rules. Errors show next to each field. Once the answers are valid, the account is created with them and the magic link or code is sent.

Changing the email while the fields are showing closes them, so the next press checks the new address.

Use registration-text to change the line above the fields, and the registration-footer slot for anything that should sit under the Create account button:

<allegro-login-form
registration-form="signup"
registration-text="Just two quick questions and you're in."
>
<p slot="registration-footer">
By creating an account you agree to our
<a href="https://acme.com/terms">terms</a>.
</p>
</allegro-login-form>

Only fields backed by user-editable attributes appear. Sign-ins through Google, Apple, or Facebook skip the questions. To ask those readers too, place an <allegro-form> in the success slot.

note

If no form matches the slug, the component signs readers in without asking any questions.

States​

The component moves through several states as the chosen sign-in flow advances. link-sent appears for the magic-link method, and code-entry for the one-time-code method (login-method="otp") and for the combined login-method="magic-link-otp" method — submitting the combined form always sends the single email and moves straight to code-entry, since the reader can either type the code there or click the link in the email. The expired state adapts its wording to match whichever method was last used.

StateTriggerDescription
emailInitial render (unauthenticated, no token in URL)Email input + social login buttons.
loadingInitial render when allegro_token is present in the URL, or while the SDK exchanges a social login's allegro_social_codeSpinner shown while the SDK validates the token.
link-sentallegro:login-form:magic-link:sent fires (magic-link method)"Check your email inbox" with a resend option.
code-entryA one-time code was requested successfully (otp or magic-link-otp method)Six code-input boxes where the reader types the code.
successInitial render (already authenticated), or a magic link / one-time code is validated successfullyCheckmark + "Welcome back" with a continue button.
expiredallegro:magic-link:failed fires, or an entered one-time code has expired or been locked"Your link has expired" with a send-new-link button.

If the user is already signed in when the component renders, it skips straight to the success state.

Slots​

Slot nameAppears in stateDescription
headeremailRendered above the email input. Use for a title or description. Values from named inputs inside this slot are included in the request data. Hidden once the form transitions to another state.
footeremailRendered below the email input (and social buttons when present). Use for supplementary links. Values from named inputs inside this slot are included in the request data. Hidden once the form transitions to another state.
after-formemailRendered between the email input and the social login buttons. Use for supplementary inputs such as newsletter opt-in checkboxes. Values from named inputs inside this slot are included in the request data, including for social logins.
registration-footeremailRendered directly below the Create account button, only while the registration fields show. Use for terms or privacy text. Values from named inputs inside this slot are included in the request data.
successsuccessReplaces the entire success state UI (icon, heading, body, and continue button). When omitted, the default success UI is shown as fallback content.
after-continuesuccessRendered directly below the continue button in the default success UI. Ignored when the success slot is provided.
<allegro-login-form publisher-name="Example News">
<div slot="header">
<h2>Sign in to continue</h2>
<p>Access your account below.</p>
</div>
<p slot="footer">
<a href="/register">Don't have an account? Sign up</a>
</p>
</allegro-login-form>

To override the entire success state:

<allegro-login-form publisher-name="Example News">
<div slot="success">
<h2>You're in!</h2>
<p>Redirecting you now…</p>
</div>
</allegro-login-form>

Shadow Parts​

For styling beyond what the CSS variables make available, elements can be targeted directly with the CSS ::part() selector.

allegro-login-form::part(email-field-input) {
margin-bottom: 2rem;
}
PartAppears in stateDescription
headingemailThe <h2> from the heading attribute. Only rendered when heading is set.
descriptionemailThe text from the description attribute. Only rendered when description is set.
email-formemailThe email input + submit button <form>.
email-fieldemailWrapper around the email label and input.
email-field-labelemailThe email input's <label> element.
email-field-inputemailThe email <input> element.
email-form-submitemailThe email submit button.
registrationemailWrapper around the registration fields. Only rendered for a new reader when registration-form is set.
registration-introemailThe line of text above the registration fields.
social-divideremailThe "OR" divider between the email form and social buttons.
social-rowemailWrapper around the social provider buttons.
social-btnemailEvery social provider button. Combined with a provider-specific part, e.g. social-btn social-btn-google.
last-used-badgeemailThe "Last used" badge. Only rendered when show-last-used is set. See Last used badge.
link-sentlink-sentWrapper around the link-sent state UI.
link-sent-iconlink-sentThe icon.
link-sent-headinglink-sentThe heading.
link-sent-bodylink-sentThe body text.
link-sent-resendlink-sentThe resend button.
code-entrycode-entryWrapper around the code-entry elements.
code-entry-iconcode-entryThe icon.
code-entry-headingcode-entryThe heading.
code-entry-bodycode-entryThe body text.
code-entry-inputcode-entryThe six-digit code input box.
code-entry-errorcode-entryThe error message under the code input.
code-entry-submitcode-entryThe verify button.
code-entry-resendcode-entryThe resend button.
successsuccessWrapper around the success elements. Not rendered when the success slot is provided.
success-iconsuccessThe icon.
success-headingsuccessThe heading.
success-bodysuccessThe body text.
success-continue-buttonsuccessThe continue button.
expired-headingexpiredThe heading.
expired-bodyexpiredThe body text.
expired-btnexpiredThe send-new-link / send-new-code button.

Events​

Dispatched​

EventBubblesDetailDescription
allegro:login-form:magic-link:sentyes{ email: string, data?: Record<string, unknown> }Fired after a magic link is successfully sent. Triggers the link-sent state.
allegro:login-form:authenticatedyes{ created: boolean } for social logins, otherwise (none)Fired on every auth flow (magic link, one-time code, and social), before any flow-specific event. Also fired on its own when a magic-link or redirect social login finished before the form loaded.
allegro:login-form:magic-link:authenticatedyes(none)Fired after a magic link is validated successfully. Follows allegro:login-form:authenticated.
allegro:login-form:third-party:authenticatedyes{ provider: string, created: boolean, session_id: string, token: string }Fired after a successful social login, through the popup or the redirect flow. Follows allegro:login-form:authenticated. provider is the provider name (e.g. google).
allegro:authenticatedno{ method: 'social', provider: string }Fired on window after a successful popup social login.
allegro:login-form:continueyes(none)Fired when the user clicks the continue button in the success state.

Listened to​

The component listens for these on window.

EventDetailDescription
allegro:magic-link:authenticated(none)Dispatched by the SDK after a magic link is validated successfully. Transitions to the success state.
allegro:magic-link:failed{ error: string }Dispatched by the SDK when magic link validation fails (e.g. expired token). Transitions to the expired state.
allegro:social:authenticated{ provider: string, created: boolean, session_id: string, token: string }Dispatched by the SDK after a redirect-based social login signs the member in. Transitions to the success state.
allegro:social:failed{ error: string }Dispatched by the SDK when a redirect-based social login fails or is canceled. Shows the email form with an error.

Tracked Events​

The component records the following analytics events via the Allegro SDK.

EventWhenData
magic_link_requestedA magic link is requested — on the initial submit, or when resent from the link-sent state.{ created: boolean }
otp_requestedA one-time code is requested — on the initial submit, or when resent from a code-entry state.{ created: boolean }
magic_link_otp_requestedA combined link and code is requested with login-method="magic-link-otp", on submit or resend.{ created: boolean }
otp_validatedA submitted one-time code is accepted and the device is authenticated.(none)
loginAuthentication completes through a popup social login, or a one-time code is accepted (provider: 'otp').{ provider: string }

created is true when a new audience member was created for the email address, and false when an existing member was matched.

note

Magic link validation is tracked separately as magic_link_validated by the SDK when the link is opened, since that happens on the page the link points to rather than within the form.

CSS Variables​

All visual properties are exposed as CSS custom properties so the component can be themed from the host page without piercing the shadow DOM.

allegro-login-form {
--loginForm--input--background: #fff;
--loginForm--submit--background: #1a1a1a;
}

Defaults written below as u(n) mean n times --loginForm--base-font-size, the component's sizing unit. The unit defaults to the page's rem. If the host page sets a root font-size other than the usual 16px, pin it so the form sizes the same either way:

allegro-login-form {
--loginForm--base-font-size: 16px;
}

General​

VariableDefaultDescription
--loginForm--base-font-sizevar(--allegro--font-size, 1rem)Base unit all internal sizing is derived from. Defaults to the document's rem. See the note below.
--loginForm--disabled--opacity0.6Opacity of disabled buttons and inputs.
--loginForm--colorvar(--allegro--color-text, var(--contentGate--color, black))Base text color for the component.
--loginForm--font-familyvar(--allegro--font-family, system-ui, sans-serif)Font family applied to the entire component.
Sizing on pages with a non-16px root

Internally the form scales every dimension — padding, font sizes, spacing — from --loginForm--base-font-size, which defaults to the page's rem. If the host page sets a root font-size other than the usual 16px (for example a 10px root), the form renders too small or too large. Pin the base to a fixed value so the form sizes consistently regardless of the host page:

allegro-login-form {
--loginForm--base-font-size: 16px;
}

Heading​

Applies to the heading and description attributes.

VariableDefaultDescription
--loginForm--heading--colorinheritHeading text color. Follows --loginForm--color by default.
--loginForm--heading--font-familyvar(--allegro--font-family-heading, inherit)Heading font family.
--loginForm--heading--font-sizeu(1.5)Heading font size.
--loginForm--heading--font-weight700Heading font weight.
--loginForm--heading--line-height1.2Heading line height.
--loginForm--description--colorvar(--allegro--color-muted, #555)Description text color.
--loginForm--description--font-sizeu(1)Description font size.

Form Layout​

VariableDefaultDescription
--loginForm--form--gapu(0.8)Gap between the field and submit button.
--loginForm--label--margin0 0 u(0.4)Margin around the email field's label.

Input​

VariableDefaultDescription
--loginForm--input--backgroundvar(--allegro--color-background, #fff)Input background color.
--loginForm--input--border1px solid var(--allegro--color-border, #8c8c8c)Input border shorthand.
--loginForm--input--border-radiusvar(--allegro--radius, u(0.375))Corner radius applied to the input.
--loginForm--input--font-sizeu(1)Input text size.
--loginForm--input--paddingu(0.75) u(1)Input padding shorthand.
--loginForm--input--focus-border-colorvar(--allegro--color-primary, #555)Border color when the input is focused.

Submit button​

VariableDefaultDescription
--loginForm--submit--backgroundvar(--allegro--color-primary, #000)Button background color.
--loginForm--submit--colorvar(--allegro--color-primary-contrast, #fff)Button text color.
--loginForm--submit--border-radiusvar(--allegro--radius, u(0.375))Corner radius applied to the button.
--loginForm--submit--font-sizeu(0.875)Button text size.
--loginForm--submit--font-weight700Button font weight.
--loginForm--submit--letter-spacing0Button letter spacing.
--loginForm--submit--font-familyinheritButton font family. Inherits the surrounding font by default.
--loginForm--submit--paddingu(0.75) u(1.25)Button padding shorthand. Buttons on the link-sent and code-entry screens use u(0.75) u(1.5).
--loginForm--submit--text-transformuppercaseCSS text-transform applied to button label.

Registration fields​

The registration fields use the same --loginForm--input--* variables as the email input, except that --loginForm--input--focus-border-color falls back to var(--allegro--color-primary, #171717) on them.

VariableDefaultDescription
--loginForm--status--colorvar(--allegro--color-primary, #000)Color of the spinner inside the email field while the email is checked.
--loginForm--status--success-color#15803dColor of the check mark shown when the email is new.
--loginForm--registration-intro--colorvar(--allegro--color-muted, #555)Color of the line of text above the registration fields.
--loginForm--registration-intro--font-sizeu(0.875)Size of the line of text above the registration fields.
--loginForm--label--font-sizeinheritSize of each registration field's label.
--loginForm--label--font-weightinheritWeight of each registration field's label.
--loginForm--required--colorvar(--allegro--color-error, #b91c1c)Color of the required-field asterisk.
--loginForm--checkbox--accent-colorvar(--allegro--color-primary, #171717)Accent color of checkbox fields.
--loginForm--tooltip--color#737373Color of a field's hint text.
--loginForm--tooltip--font-sizeu(0.75)Size of a field's hint text.
--loginForm--error--font-sizeu(0.875)Size of a field's error message, and of the error on the code-entry screen.

Divider​

VariableDefaultDescription
--loginForm--divider--colorvar(--allegro--color-muted, #333)Text and line color for the "OR" divider.
--loginForm--divider--line-colorcurrentColorOverride only the line color independently.
--loginForm--divider--marginu(1) 0Vertical spacing around the divider.
--loginForm--divider--font-sizeu(0.8125)Divider label font size.
--loginForm--divider--letter-spacing0.08emDivider label letter spacing.

Social buttons​

VariableDefaultDescription
--loginForm--social--backgroundvar(--allegro--color-background, #fff)Social button background color.
--loginForm--social--hover-background#f9fafbSocial button background on hover.
--loginForm--social--border1px solid var(--allegro--color-border, #d1d5db)Social button border shorthand.
--loginForm--social--border-radiusvar(--allegro--radius, u(0.5))Social button corner radius.
--loginForm--social--colorvar(--allegro--color-text, #111)Social button text color.
--loginForm--social--font-familyinheritSocial button font family. Inherits the surrounding font by default.
--loginForm--social--font-sizeu(1)Social button text size. When unset, labels shrink to fit narrow buttons (down to 0.75rem). Unset, the button label scales with the button width between 0.75em and 1em.
--loginForm--social--line-height1.25Social button line height.
--loginForm--social--height42pxMinimum button height when the buttons are stacked.
--loginForm--social--height-desktop48pxMinimum button height when the buttons sit side by side.
--loginForm--social--paddingu(0.5) u(1)Social button padding shorthand. Defaults to 0.5rem 0.75rem when the buttons sit side by side. Side-by-side buttons use u(0.5) u(0.75).
--loginForm--social--gapu(0.5)Gap between social buttons when stacked; same value applies in the side-by-side layout.
--loginForm--social--font-weight500Social button font weight.
--loginForm--social--min-width0Minimum width of each social button.

Last used badge​

Only rendered when the show-last-used attribute is set. Also exposed as the last-used-badge shadow part for full style overrides.

VariableDefaultDescription
--loginForm--last-used--background#dbeafeBadge background color.
--loginForm--last-used--color#1e40afBadge text color.
--loginForm--last-used--border1px solid #bfdbfeBadge border shorthand.
--loginForm--last-used--shadow0 1px 2px rgba(0, 0, 0, 0.15)Badge drop shadow (box-shadow).
--loginForm--last-used--border-radius999pxBadge corner radius.
--loginForm--last-used--font-familyinheritBadge font family.
--loginForm--last-used--font-sizeu(0.6875)Badge text size.
--loginForm--last-used--font-weight500Badge font weight.
--loginForm--last-used--paddingu(0.125) u(0.5)Badge padding shorthand.
--loginForm--last-used--offset-xu(-0.5)Horizontal offset of the badge from the button's right edge.
--loginForm--last-used--offset-yu(-0.5)Vertical offset of the badge from the button's top edge.

Loading spinner​

VariableDefaultDescription
--loginForm--loading--track-colorcurrentColorSpinner color. Inherits the component text color by default.
VariableDefaultDescription
--loginForm--state-icon--backgroundvar(--allegro--color-primary, #111)Background color of the circular state icon.
--loginForm--state-heading--colorvar(--allegro--color-text, #111)Heading text color.
--loginForm--state-heading--font-sizeu(1.25)Heading font size.
--loginForm--state-heading--font-weight700Heading font weight.
--loginForm--state-body--colorvar(--allegro--color-muted, #555)Body and disclaimer text color.
--loginForm--state-body--font-sizeu(0.9375)Body text size.
--loginForm--state-icon--sizeu(3.5)Width and height of the state screen icon.
--loginForm--resend--colorvar(--allegro--color-muted, #555)Resend link text color. The code-entry screen falls back to #374151 instead.
--loginForm--resend--hover-colorvar(--allegro--color-text, #111)Resend link text color on hover.
--loginForm--resend--font-sizeu(0.875)Resend link font size.
--loginForm--resend-error--colorvar(--allegro--color-error, #b91c1c)Text color for the inline error shown below the resend/send-new-link button.

Code entry​

VariableDefaultDescription
--loginForm--otp--padding-inlineu(0.75)Horizontal padding around the code-entry inputs.
--loginForm--otp-input--font-sizeu(1.75)Font size of each code-entry digit.
--loginForm--otp-input--heightu(3.25)Height of each code-entry input.

Error message​

VariableDefaultDescription
--loginForm--error--background#fef2f2Error container background color.
--loginForm--error--border1px solid #fecacaError container border shorthand.
--loginForm--error--accent-colorvar(--allegro--color-error, #dc2626)Left accent border color.
--loginForm--error--border-radiusvar(--allegro--radius, u(0.375))Error container corner radius.
--loginForm--error--colorvar(--allegro--color-error, #b91c1c)Error message text color.
--loginForm--error--icon-colorcurrentColorError icon color (inherits text color by default).
--loginForm--error--paddingu(0.625) u(0.875)Error container padding.

Example: Dark Background​

When placing the component on a dark or colored background, override the divider and social button colors so they read clearly:

allegro-login-form {
--loginForm--divider--color: rgba(255, 255, 255, 0.7);
--loginForm--social--background: transparent;
--loginForm--social--border: 1px solid rgba(255, 255, 255, 0.4);
--loginForm--social--color: #fff;
--loginForm--social--hover-background: rgba(255, 255, 255, 0.08);
}