KQ-1709 · ORG/DISCOVERY
Org Discovery
A sign-in step that finds a company's own sign-in from the email domain. When a typed domain is recognised, a wash appears behind the domain's own letters — found to the pixel from a hidden mirror of the field's text — and lifts off them onto the field's top edge, growing into a badge with the company's mark on springs.glide while its shadow swells in flight and settles; the main button's words roll to single sign-on on springs.snap and the password folds away to its measured height on glide. Change the address and the badge drops back into the field where the domain now starts; it is a real form, so Tab, Enter and the announcements all behave as a sign-in should.
waiting for an address · type your work email
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/org-discovery
Props
- orgs
- OrgDiscoveryOrg[]
- default defaultOrgDiscoveryOrgs
- Companies with their own sign-in: { id, name, domains, methods, provider?, tint? }.
- lookup
- (domain) => Promise<OrgDiscoveryOrg | null>
- default matches orgs
- Looks a domain up elsewhere; resolve null for unknown. A rejection falls back quietly to the password and code.
- lookupDelay
- number
- default 280
- Quiet time after typing before a domain is looked up, in ms.
- value / defaultValue
- string
- default — / ""
- The email, controlled or initial.
- onValueChange
- (email) => void
- default —
- Fires from every keystroke in the email field.
- onContinue
- (details) => void | Promise<void>
- default —
- The main button was pressed with { email, method: "sso" | "password", org, password? }. A promise holds it busy; a rejection keeps the step and shows its message under the field it concerns.
- onUseOtherMethod
- (method: "code" | "password", email) => void
- default —
- "Email me a sign-in code" or "Use a password instead" was pressed.
- onForgotPassword
- (email) => void
- default —
- "Forgot password?" was pressed.
- onOrgChange
- (org | null) => void
- default —
- The recognised company changed, reported from the lookup or the keystroke that changed it.
- onCreateAccount
- () => void
- default —
- "Create an account" was pressed under the form.
- error
- string
- default —
- A message from the host about the last attempt, shown under the field it concerns.
- productName
- string
- default "Waylight"
- Your product's name, used in the heading, the aside and the footer.
- title
- string
- default "Sign in to {productName}"
- The heading that names the form.
- badgeStyle
- "chip" | "tag" | "mark"
- default "chip"
- The lifted domain as a pill with mark and name, a tag with an SSO segment, or the mark alone.
- density
- "compact" | "cozy" | "roomy"
- default "cozy"
- Field height, gaps and type size.
- accent
- string
- default "var(--accent-bright)"
- The wash, the tether under the domain, the main button and links, any CSS colour; the button's ink adapts to its lightness.
- showAside
- boolean
- default true
- Show the explanatory side panel when the container is 40rem or wider.
- autoFocus
- boolean
- default false
- Focus the email field on mount.
- disabled
- boolean
- default false
- Nothing can be typed or pressed.
- className
- string
- default —
- Classes for the wrapper.
| Prop | Type | Default | Description |
|---|---|---|---|
| orgs | OrgDiscoveryOrg[] | defaultOrgDiscoveryOrgs | Companies with their own sign-in: { id, name, domains, methods, provider?, tint? }. |
| lookup | (domain) => Promise<OrgDiscoveryOrg | null> | matches orgs | Looks a domain up elsewhere; resolve null for unknown. A rejection falls back quietly to the password and code. |
| lookupDelay | number | 280 | Quiet time after typing before a domain is looked up, in ms. |
| value / defaultValue | string | — / "" | The email, controlled or initial. |
| onValueChange | (email) => void | — | Fires from every keystroke in the email field. |
| onContinue | (details) => void | Promise<void> | — | The main button was pressed with { email, method: "sso" | "password", org, password? }. A promise holds it busy; a rejection keeps the step and shows its message under the field it concerns. |
| onUseOtherMethod | (method: "code" | "password", email) => void | — | "Email me a sign-in code" or "Use a password instead" was pressed. |
| onForgotPassword | (email) => void | — | "Forgot password?" was pressed. |
| onOrgChange | (org | null) => void | — | The recognised company changed, reported from the lookup or the keystroke that changed it. |
| onCreateAccount | () => void | — | "Create an account" was pressed under the form. |
| error | string | — | A message from the host about the last attempt, shown under the field it concerns. |
| productName | string | "Waylight" | Your product's name, used in the heading, the aside and the footer. |
| title | string | "Sign in to {productName}" | The heading that names the form. |
| badgeStyle | "chip" | "tag" | "mark" | "chip" | The lifted domain as a pill with mark and name, a tag with an SSO segment, or the mark alone. |
| density | "compact" | "cozy" | "roomy" | "cozy" | Field height, gaps and type size. |
| accent | string | "var(--accent-bright)" | The wash, the tether under the domain, the main button and links, any CSS colour; the button's ink adapts to its lightness. |
| showAside | boolean | true | Show the explanatory side panel when the container is 40rem or wider. |
| autoFocus | boolean | false | Focus the email field on mount. |
| disabled | boolean | false | Nothing can be typed or pressed. |
| className | string | — | Classes for the wrapper. |