Detent web components
By Shane Logsdon

Commerce & auth

Login

Implemented

Refined authentication card with validation & social SSO

detent-login

Port status
Catalog status
implemented
Origin
upstream
Phase
3
Wave
phase-3-data
Group
Commerce & auth

6.9 KB gzip for the class module

Variants

Every card validates like the upstream component: submit with an empty field to see the inline role="alert" messages, and use the eye button to reveal the password. The first card here shows the server-error banner, the second is in its loading state (the submit label stays legible and the button is disabled). SSO, forgot-password and sign-up each emit one composed event; the demo never authenticates, it only reports what the user entered.

Recorded states

  • focus-visible recorded state; no setter
  • loading recorded state; no setter
  • error recorded state; no setter

Usage

Import

import '/components/login/define.js';

// or register it yourself
import { DetentLogin } from '/components/login/login.js';

Attributes

  • description
  • error
  • is-loading
  • show-social-logins
  • sign-up-text
  • title

Properties

  • onForgotPassword
  • onSignUpClick
  • onSocialLogin
  • onSubmit

Slots

  • logo

Events

  • detent-submit — {}
  • detent-forgot-password — {}
  • detent-sign-up-click — {}
  • detent-social-login — {}

Example

Runnable example: site/examples/login.ts. The snippet below is generated from the catalogued attributes.

<detent-login
  description
  error
  is-loading
  show-social-logins
  sign-up-text
  title="Welcome back"
></detent-login>

Property-only values

const element = document.querySelector('detent-login');
if (element !== null) {
  // onSubmit: (data: LoginFormData) => void
  element.onSubmit = () => {};
  // onForgotPassword: () => void
  element.onForgotPassword = () => {};
  // onSignUpClick: () => void
  element.onSignUpClick = () => {};
  // onSocialLogin: (provider: 'github' | 'google' | 'apple') => void
  element.onSocialLogin = () => {};
}

Source

The pinned upstream source for this row:

  • src/components/ui/Login.tsx sha256 3dc8d9a7d75d…

Native files

The native module and its artifacts:

  • src/components/login/login.ts
  • src/components/login/styles.css
  • src/components/login/define.ts
  • docs/components/login.md
  • site/examples/login.ts
  • tests/browser/login.spec.ts
  • evidence/components/login.md

API

Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.

Attributes

Attributes
AttributePropertyTypeDefaultNotes
descriptiondescriptionstringSign in to access your Detent workspaceKebab-case attribute; camelCase property.
errorerrorstring | nullnullKebab-case attribute; camelCase property.
is-loadingisLoadingbooleanfalsePresence semantics: present means true, absent means false.
show-social-loginsshowSocialLoginsbooleantruePresence semantics: present means true, absent means false.
sign-up-text———Recorded in the catalog as an attribute.
titletitlestring'Welcome back'Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
onForgotPassword() => voidundefinedProperty-only: assign from script; not accepted as an attribute.
onSignUpClick() => voidundefinedProperty-only: assign from script; not accepted as an attribute.
onSocialLogin(provider: 'github' | 'google' | 'apple') => voidundefinedProperty-only: assign from script; not accepted as an attribute.
onSubmit(data: LoginFormData) => voidundefinedProperty-only: assign from script; not accepted as an attribute.

Events

Events
EventUpstream propPayload typeNotes
detent-submitonSubmit(data: LoginFormData) => voidComposed, bubbles; fires only for a user action.
detent-forgot-passwordonForgotPassword() => voidComposed, bubbles; fires only for a user action.
detent-sign-up-clickonSignUpClick() => voidComposed, bubbles; fires only for a user action.
detent-social-loginonSocialLogin(provider: 'github' | 'google' | 'apple') => voidComposed, bubbles; fires only for a user action.

Slots

Slots
SlotNotes
logoConsumer content; rendered through a slot, never re-created.

CSS customisation

  • React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • Forgot-password and sign-up affordances are always rendered. Upstream renders them only when the corresponding callback prop exists. A custom element always has the event, so hiding the affordance would remove discoverable UI; the secondary row hides only when sign-up-text="".
  • className is not an attribute. Consumer styling uses the documented parts and custom properties (PC-9.4).
  • React ReactNode logo becomes the logo slot; the Lucide Sparkles default is a local SVG (PC-11.5).
  • Framer Motion springs become CSS transitions, and AnimatePresence's mount/unmount of the error banner becomes hidden toggling so the live region stays in the tree for reliable announcements.
  • Callbacks become composed events plus optional property hooks; property writes emit no event (PC-6.5).
  • The field boundary uses a stronger grey than upstream's #1F1F1F so the input boundary reaches 3:1 (WCAG 1.4.11). Dividers keep the upstream hairline.
  • Validation is client-side only and the card never authenticates; it emits detent-submit and leaves the decision to the consumer (demo widget, no network).
  • Default demo copy and labels use Detent branding instead of EasyUI (pre-release rebrand).

What it does

A refined authentication card: a slotted logo, a title and description, an optional server-error banner, GitHub and Google SSO, a validated email/password form with a password visibility toggle, a remember-me checkbox and the secondary "sign up" link.

Upstream behaviour
  • Built with EasyUI Form & Button architecture
  • Interactive password visibility toggle with Lucide icons
  • Form validation for required fields & email regex format
  • Spring-animated error banners and inline field alerts
  • Configurable social SSO buttons (GitHub & Google)
  • Remember me checkbox and "Forgot password?" callback hooks
  • Responsive mobile/desktop dimensions with atmospheric glow header
Differences from upstream
  • React `children`/`ReactNode` props become DOM slots; caller content stays light DOM.
  • React callback props become typed composed CustomEvents; programmatic state assignment emits none.
  • Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
  • `lucide-react` icon components replaced with local SVG assets (ISC notice retained).
  • React state/hooks replaced by element-owned state with pre-upgrade property preservation.
  • Forgot-password and sign-up affordances are always rendered. Upstream renders them only when the corresponding callback prop exists. A custom element always has the event, so hiding the affordance would remove discoverable UI; the secondary row hides only when sign-up-text="".
  • className is not an attribute. Consumer styling uses the documented parts and custom properties (PC-9.4).
  • React ReactNode logo becomes the logo slot; the Lucide Sparkles default is a local SVG (PC-11.5).
  • Framer Motion springs become CSS transitions, and AnimatePresence's mount/unmount of the error banner becomes hidden toggling so the live region stays in the tree for reliable announcements.
  • Callbacks become composed events plus optional property hooks; property writes emit no event (PC-6.5).
  • The field boundary uses a stronger grey than upstream's #1F1F1F so the input boundary reaches 3:1 (WCAG 1.4.11). Dividers keep the upstream hairline.
  • Validation is client-side only and the card never authenticates; it emits detent-submit and leaves the decision to the consumer (demo widget, no network).
  • Default demo copy and labels use Detent branding instead of EasyUI (pre-release rebrand).
Previous: LockInput Next: Folder Cards

Docs

Components

Project