Detent web components
By Shane Logsdon

Commerce & auth

Sign Up

Implemented

Multi-step capable user registration with strength telemetry

detent-sign-up

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

8.6 KB gzip for the class module

Variants

Sample data; nothing is fetched or sent. Type a password to see the four-tier strength meter, submit an empty form to see the five inline role="alert" messages, and use either eye button to reveal a password. The loading card disables submission and shows the spinner; the last card is shown with its two default-true flags resolved (both stay on until the property opts out). All three events are composed and bubble.

Recorded states

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

Usage

Import

import '/components/sign-up/define.js';

// or register it yourself
import { DetentSignUp } from '/components/sign-up/sign-up.js';

Attributes

  • description
  • error
  • is-loading
  • require-confirm-password
  • show-social-sign-up
  • sign-in-text
  • title

Properties

  • onSignInClick
  • onSocialSignUp
  • onSubmit
  • formData

Slots

  • logo
  • terms-text

Events

  • detent-submit — {}
  • detent-sign-in-click — {}
  • detent-social-sign-up — {}

Example

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

<detent-sign-up
  description="Join Detent to access components and templates"
  error
  is-loading
  require-confirm-password
  show-social-sign-up
  sign-in-text
  title="Create an account"
></detent-sign-up>

Property-only values

const element = document.querySelector('detent-sign-up');
if (element !== null) {
  // onSubmit: (data: SignUpFormData) => void
  element.onSubmit = () => {};
  // onSignInClick: () => void
  element.onSignInClick = () => {};
}

Source

The pinned upstream source for this row:

  • src/components/ui/SignUp.tsx sha256 e24b677da41e…

Native files

The native module and its artifacts:

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

API

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

Attributes

Attributes
AttributePropertyTypeDefaultNotes
descriptiondescriptionstring'Join Detent to access components and templates'Kebab-case attribute; camelCase property.
errorerrorstring | nullnullKebab-case attribute; camelCase property.
is-loadingisLoadingbooleanfalsePresence semantics: present means true, absent means false.
require-confirm-passwordrequireConfirmPasswordbooleantruePresence semantics: present means true, absent means false.
show-social-sign-upshowSocialSignUpbooleantruePresence semantics: present means true, absent means false.
sign-in-text———Recorded in the catalog as an attribute.
titletitlestring'Create an account'Kebab-case attribute; camelCase property.

Properties

Properties
PropertyTypeDefaultNotes
onSignInClick() => voidundefinedProperty-only: assign from script; not accepted as an attribute.
onSocialSignUp——Recorded in the catalog without a top-level type; pinned from source when the row is ported.
onSubmit(data: SignUpFormData) => voidundefinedProperty-only: assign from script; not accepted as an attribute.
formData——Recorded in the catalog without a top-level type; pinned from source when the row is ported.

Events

Events
EventUpstream propPayload typeNotes
detent-submitonSubmit(data: SignUpFormData) => voidComposed, bubbles; fires only for a user action.
detent-sign-in-clickonSignInClick() => voidComposed, bubbles; fires only for a user action.
detent-social-sign-uponSocialSignUp(provider: 'github' | 'google') => voidComposed, bubbles; fires only for a user action.

Slots

Slots
SlotNotes
logoConsumer content; rendered through a slot, never re-created.
terms-textConsumer 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.
  • The sign-in affordance is always rendered (upstream renders it only when onSignInClick exists); the element always exposes detent-sign-in-click.
  • show-social-sign-up and require-confirm-password default to true, are reflected while connected, and the property is the opt-out (presence semantics, PC-3.2).
  • The error banner toggles hidden instead of unmounting, so the role="alert" region stays in the tree for reliable announcements.
  • Framer Motion springs become CSS transitions; the submit spinner is a static glyph under prefers-reduced-motion: reduce.
  • The field boundary uses #6b6b6b so it reaches the WCAG 1.4.11 3:1 non-text ratio; dividers keep the upstream hairline.
  • The pinned card was one fixed dark panel because the source has no dark: variants; this port follows the theme tokens in both colour schemes, and --detent-sign-up-* custom properties still override every value.
  • The terms links are associated with the required checkbox through aria-labelledby instead of being nested inside the label, so both links stay independently focusable (PC-12.6).
  • A failed submit moves focus to the first invalid control (PC-12.6).
  • The password-strength meter is role="status" with aria-live="polite" (PC-12.5).
  • detail.data always carries confirmPassword, as the string "" when the confirmation field is hidden, matching the pinned source's unconditional argument.
  • className is replaced by the documented CSS parts and custom properties; logos and the cloud glyph are local inline SVG, not lucide-react.
  • ReactNode props become slots (logo, terms-text) with local fallbacks.
  • Client-side validation only: the element never authenticates, stores or transmits credentials and makes no network request.
  • Default demo copy and labels use Detent branding instead of EasyUI (pre-release rebrand).

What it does

A registration card: a slotted logo, title and description, an optional server-error banner, GitHub and Google SSO, a validated four-field form with two password visibility toggles, the live four-tier strength meter, the terms checkbox and the secondary sign-in action.

Upstream behaviour
  • Integrated live 4-tier password strength indicator bar
  • Password confirmation matching validation
  • Interactive eye icons for show/hide password visibility
  • Terms of service and privacy agreement checkbox validation
  • Customizable social onboarding SSO buttons (GitHub & Google)
  • Submitting state with monochrome button spinner
  • Responsive layout with atmospheric glow and dark slate tokens
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.
  • The sign-in affordance is always rendered (upstream renders it only when onSignInClick exists); the element always exposes detent-sign-in-click.
  • show-social-sign-up and require-confirm-password default to true, are reflected while connected, and the property is the opt-out (presence semantics, PC-3.2).
  • The error banner toggles hidden instead of unmounting, so the role="alert" region stays in the tree for reliable announcements.
  • Framer Motion springs become CSS transitions; the submit spinner is a static glyph under prefers-reduced-motion: reduce.
  • The field boundary uses #6b6b6b so it reaches the WCAG 1.4.11 3:1 non-text ratio; dividers keep the upstream hairline.
  • The pinned card was one fixed dark panel because the source has no dark: variants; this port follows the theme tokens in both colour schemes, and --detent-sign-up-* custom properties still override every value.
  • The terms links are associated with the required checkbox through aria-labelledby instead of being nested inside the label, so both links stay independently focusable (PC-12.6).
  • A failed submit moves focus to the first invalid control (PC-12.6).
  • The password-strength meter is role="status" with aria-live="polite" (PC-12.5).
  • detail.data always carries confirmPassword, as the string "" when the confirmation field is hidden, matching the pinned source's unconditional argument.
  • className is replaced by the documented CSS parts and custom properties; logos and the cloud glyph are local inline SVG, not lucide-react.
  • ReactNode props become slots (logo, terms-text) with local fallbacks.
  • Client-side validation only: the element never authenticates, stores or transmits credentials and makes no network request.
  • Default demo copy and labels use Detent branding instead of EasyUI (pre-release rebrand).
Previous: Sidebar Next: Skeleton

Docs

Components

Project