Skip to main content


<Form> renders a configurable form that can be used to sign in or sign up users. A <ConfigurationProvider> needs to be rendered as a parent component, preferably near the application root component to reduce the number of re-renders.


import { ConfigurationProvider, Form } from "@slashid/react"
import "@slashid/react/style.css"

function SignIn() {
return (
<Form />

The default styles must be imported:
import "@slashid/react/style.css"

Note: if using Parcel the CSS import line should be changed to:
import "@slashid/react/dist/style.css"


onSuccess?(user: User) => voidCallback function that gets called with a User object returned from core SDK upon successful log in action
middleware?LoginMiddleware | LoginMiddleware[]Effects to be run post-login but before onSuccess fires, and before the next render cycle. See LoginMiddleware for more.
factors?Factor[]Override for the available authentication factors set by <ConfigurationProvider>.
text?Record<string, string>Overrides for the text shown in the form. See <ConfigurationProvider> default text key-value pairs.
children?Slot<"initial" | "authenticating" | "error" | "success" | "footer">Named slots to be replaced with custom implementation.

Configuration should be done through the <ConfigurationProvider>, but if you wish you can override it using the factors and text props.

UI customization

The primary way of customizing the form appearance is by using CSS custom properties. Additionally, the individual form element styles can be overridden using plain CSS.

CSS custom properties (variables)

A set of CSS custom properties is used to define the basic look and feel of the <Form>. There are two ways of overriding the default values of these properties:

  • use a global CSS selector: sid-theme-root
  • passing in a custom class name to the <Form> using the className prop

Both of these approaches can be used to specify any of the following properties values:


For example, in order to the change the font-family you could specify the following:

.sid-theme-root {
--sid-font-family: Inter

Overriding CSS rules

If you inspect the form elements using the developer tools in your browser, you'll notice that they have a set of class names applied. Within this set some class names are stable, while others are hash based and dynamic. Class names prefixed by sid-- are stable and act as a public API for overriding the CSS rules. For example, you could customize the button element by using a selector like this:

.sid-button {
color: red;

Layout slots & primitives

The form layout is composed of a set of named slots that can be used to customize the layout. The slots and their rendering conditions are as follows:

  • initial - rendered when the form is first displayed, can be used to render the form fields
  • authenticating - rendered while the user is being authenticated
  • error - rendered when an error occurs
  • success - rendered when the user is successfully authenticated
  • footer - rendered at the bottom of the form, regardless of the form state

When rendering Form without replacing any slots with custom components, it will render in its default state. The following screenshot shows the default form layout in the initial state with the slots outlined:

Form slots

The following example shows how to use these slots:

import { Slot, Form } from "@slashid/react"

function CustomForm() {
return (
<Slot name="authenticating">
<p>Please wait...</p>
<Slot name="success">
<p>You are logged in!</p>
<Slot name="error">
<p>An error happened!</p>
<Slot name="footer">
<footer>My custom footer</footer>

We haven't used the initial slot in this example, so the default form fields will be rendered. If you also want to customise the way the form fields are being rendered, you can compose the <Form> using the primitives we export under the Form namespace.

Composing a custom Form


Check the Form composition guide for a more detailed explanation of how to compose a custom form.

When replacing the default form fields using <Slot name="initial">, you can use a set of primitives designed to make it easier to compose the form. In order to use these knowing a couple of interfaces will be helpful:


The primitive components used to build out the initial state of the form are all exposed under the Form.Initial namespace. This namespace has the following components:

ComponentChildren as a function propsDescription
Form.Initial.LogoRenders the configured logo.
Form.Initial.HeaderRenders the header with text content.
Form.Initial.Controls{ factors: Factor[], handleTypes: HandleType[], handleSubmit: (factor: Factor, handle?: Handle) => void }Wraps children with a <form> that has a submit listener attached.
Form.Initial.OIDCRenders a button per each configured OIDC factor.

The form is designed to be composed of these primitives. You can add additional components of your own anywhere within the slot.

The Form.Initial.Controls component is the most complex one, as it renders the form fields and the submit button. We can break the form down further by passing children to this component. There are two options for passing children to this component:

  • building a completely custom form by passing in a function as a child
  • passing in a ReactNode as a child and composing the form fields using the primitives from the Form.Initial.Controls namespace and your components

The following table lists the components that can be used to compose the form fields:

ComponentChildren as a function propsDescription
Form.Initial.Controls.Input{ factors: Factor[], handleTypes: HandleType[] }Renders the appropriate form fields based on the factors being used.
Form.Initial.Controls.Submit{ status: FormStatus }Renders the submit button.

You can freely mix and match these components to create your own form layout. Any children passed to <Slot name="initial"> will be rendered accordingly, including the primitives listed above and your own components.

Alternatively they accept children as a function, which is called with the props listed above. This will make you responsible for rendering the UI, while giving you access to the props to reuse the behaviour of the default implementation. For example:

function ComposedForm({ handleSubmit }) {
const [email, setEmail] = useState("")

return (
onSubmit={(e) => {
handleSubmit({ method: "email_link" }, { type: "email_address", value: email })
<input type="email" value={email} onChange={(e) => setEmail(} />
<Form.Initial.Controls.Submit />

We first created our own <ComposedForm> component that renders a form with a custom email input and a submit button that uses the default implementation. We then wrap this component with <Form.Initial.Controls> to get access to the handleSubmit prop, which we use to submit the form:

import { Slot, Form } from "@slashid/react"

function CustomForm() {
return (
<Slot name="initial">
{({ handleSubmit }) => {
return <ComposedForm handleSubmit={handleSubmit} />

In this contrived example we illustrated how to compose the form using our primitives or your own components. In practice you'll probably want to use the default implementation for most of the form fields, and only replace the ones you want to customize.

Multi-Factor Authentication

See <MultiFactorAuth> component reference.