SocialLogin
The row of 'Continue with Google/Apple/GitHub' buttons under a sign-in form, with bundled brand logos for ten providers — stacked and labelled, or icon-only side by side. Emits `select` with the provider's id; starting the OAuth flow is yours. Already built into `LoginForm`/`SignupForm` via their `providers` prop.
<UiSocialLogin :providers="..." />Options
One block per prop — what it does, and what it looks like set.
Providers
requiredproviders is the list of buttons, in order. A bare string uses the bundled brand name and logo — google, apple, microsoft, github, gitlab, facebook, discord, x, twitter, instagram. Anything else is an object: id is what select emits, and name/logo/icon fill in what no bundled mark covers, like your own SSO.
The ten bundled marks ship as SVGs inside the package — no network request, no icon font, and nothing to configure. They're the real brand colors on a dark background (GitHub, X and Apple are the white variants), so they're drawn for this library's dark theme rather than tinted to your accent color.
An id with no bundled mark and no logo/icon of its own still renders: the name is the id title-cased and the mark falls back to the login icon. That's a legible placeholder, not a silent hole — but pass a name and a logo for anything you actually ship.
Each button renders type="button", so dropping this inside your own <form> never submits it by accident — a bare <button> in a form defaults to type="submit".
Layout
layout chooses between a full-width labelled button per provider (stacked) and one icon-only button each, side by side (inline). Stacked stays readable at any number of providers and reads as the alternative it is; inline costs one row no matter how many there are, and is what to reach for once you're offering four or more.
stacked
inline
inline drops the provider name from the button face; it survives only as the aria-label and the hover title. That's fine for marks people recognise instantly (Google, Apple, GitHub) and bad for your own SSO badge — use stacked there.
Label
label is the verb in front of each provider's name. 'Continue with' is deliberately neutral — it's the same button whether the account already exists or not, which is how OAuth actually behaves. Set it to 'Sign up with' on a registration screen, where the promise matters more than the accuracy.
Divider
divider is the word in the labelled rule above the buttons — it's what tells a reader these are an alternative to the form above rather than a next step. Pass false where there's nothing above them to be an alternative to.
or continue with
Variant
variant is passed straight through to each Button. subtle is the default and the safe one: filled enough to read as a button, quiet enough not to compete with the form's own solid submit. solid deliberately does compete — don't use it where an email/password form is the primary path.
subtle
soft
ghost
Size
size is passed through to each Button, and the logos follow it — 16px marks on sm, 20px on md and lg.
sm
md
lg
Loading
loading takes the id of the provider whose redirect is in flight: that button swaps its logo for a spinner and the rest go disabled, so a second click can't start a competing flow. Pass true instead to disable them all without a spinner — that's what LoginForm does with its own loading, where the request running belongs to the form above.
Disabled
disabled switches every button off without a spinner anywhere — for a screen that hasn't finished loading its config, or a tenant whose SSO is enforced elsewhere.
Examples
The component in real use: compositions that answer "how do I build X with this", rather than one prop at a time.
Driving the flow from `select`
select hands you the provider's id and nothing else — the redirect, the popup, the callback route are all yours. Track which one is in flight in your own state and pass it back as loading.
This component doesn't sign anyone in
SocialLogin renders buttons and emits select with an id. There's no OAuth client in here — wire select to your own auth SDK (Supabase, Auth.js, Better Auth, your backend's /auth/:provider route).
API Reference
Generated from the component's source — props, slots and emits as the component actually declares them.
Props
providersrequired(SocialProviderId | SocialProvider)[]"stacked" | "inline"'stacked'string'Continue with'string | false'or'"solid" | "subtle" | "soft" | "ghost"'subtle'boolean | stringfalseEmits
select[id: string]Types
type SocialProviderId = "google" | "apple" | "microsoft" | "github" | "gitlab" | "facebook" | "discord" | "x" | "twitter" | "instagram";type Variant = "solid" | "subtle" | "soft" | "ghost";interface SocialProvider {
/**
* Identifier emitted by `select` — use it in your handler to pick which OAuth flow to start.
* Matching a `SocialProviderId` also supplies the brand name and logo for free.
*/
id: string;
/**
* The provider's brand name, rendered after the `label` verb ('Continue with **Google**').
* Defaults to the brand name for a built-in id, or the id itself, title-cased.
*/
name?: string;
/**
* URL of the provider's logo, rendered as an `<img>`. Defaults to the bundled brand mark for a
* built-in id.
*/
logo?: string;
/**
* A bundled icon name to render instead of a logo image — for a provider with no brand mark of
* its own (SAML, a magic link, your own SSO).
*/
icon?: string;
}