Customization
Start with the zero-effort default and adopt customization only as far as you need.
| Effort | Control | What you use | Best for | |
|---|---|---|---|---|
| Default | None | Low | HaapiStepper + HaapiStepperStepUI | getting HAAPI flows running out of the box |
| Styles customization | Very low | Look only | CSS classes (.haapi-stepper-*) | restyling the default UI |
| Render interceptors | Low | Medium | HaapiStepperStepUI + interceptor props | tweaking the default UI |
| UI composition | High | Full | HaapiStepper + useHaapiStepper hook + UI components | custom layout, grouping, complex/behaviour |
| Mixed | Mixed | Full | a combination of the above | the default UI with localized custom parts |
Default — works from scratch
Renders the complete HAAPI flow UI.
Styles customization
The UI components emit plain .haapi-stepper-* CSS class names — restyle the default UI just by
overriding those classes in your own stylesheet, no code changes needed.
CSS customization
The HAAPI UI components are styled via plain CSS class names — no CSS-in-JS, no inline styles. The components only emit class names; the actual rules live in a stylesheet shipped alongside the host application's global stylesheet. For example, in the case of the haapi-react-app, in haapi-react-app/src/shared/util/css/styles.css.
Importing CSS styles
Import the stylesheet once from the consuming application's entry point (e.g. main.tsx):
import './shared/util/css/styles.css';
By default, the rules in styles.css compose utility classes from Curity CSS Library (imported at the top of the file) using PostCSS @extend — e.g. .haapi-stepper-button { @extend .button, .button-medium, .button-primary, .w100, .mt2; }. The components themselves only know about the .haapi-stepper-* class names, so consumers are free to back those classes with anything they like.
Overriding or extending the defaults
Because the components emit static class names, consumers can:
- Override / Extend: define rules for the same class names — or append additional CSS — in a separate stylesheet imported after
styles.css. - Replace: skip the default import entirely and provide your own definitions for the classes listed below — written in plain CSS, or composed from any third-party library, for example Tailwind CSS.
The Curity utility composition shown above is just how this project chose to implement the defaults; it is not a contract. Nothing in the components requires @curity/ui-kit-css, PostCSS, or @extend.
Available CSS classes
| Class | Used by | Purpose |
|---|---|---|
.haapi-stepper-selector | HaapiStepperSelectorUI | Selector action container |
.haapi-stepper-authenticator-button | HaapiStepperFormSubmitButton | Authenticator-selector option button (applied automatically when the action carries authenticatorType); combine with .button-<authenticatorType> (e.g. .button-google) to get the per-authenticator icon color |
.haapi-stepper-messages | HaapiStepperMessagesUI | Messages container |
.haapi-stepper-form-field-text-input | HaapiStepperTextFormFieldUI | Text input fields |
.haapi-stepper-form-field-text-label | HaapiStepperTextFormFieldUI | Form field labels |
.haapi-stepper-form-field-checkbox-input | HaapiStepperCheckboxFormFieldUI | Checkbox inputs |
.haapi-stepper-form-field-checkbox-label | HaapiStepperCheckboxFormFieldUI | Checkbox-specific labels |
.haapi-stepper-form-field-select-input | HaapiStepperSelectFormFieldUI | Select inputs |
.haapi-stepper-form-field-select-label | HaapiStepperSelectFormFieldUI | Select-specific labels |
.haapi-stepper-form-field-password-wrapper | HaapiStepperPasswordFormFieldUI | Password input container |
.haapi-stepper-form-field-password-label | HaapiStepperPasswordFormFieldUI | Password label |
.haapi-stepper-form-field-password-input | HaapiStepperPasswordFormFieldUI | Password input |
.haapi-stepper-form-field-password-visibility-toggle | HaapiStepperPasswordFormFieldUI | Password visibility toggle button |
.haapi-stepper-button | HaapiStepperFormUI | Primary submit buttons |
.haapi-stepper-button-outline | HaapiStepperFormUI | Outline/cancel buttons |
.haapi-stepper-well | Well | Styled content container |
.haapi-stepper-links | HaapiStepperLinksUI | Links container |
.haapi-stepper-link | HaapiStepperLinkUI | Link element |
.haapi-stepper-link-qr-code | HaapiStepperLinkUI | QR code link figure wrapper |
.haapi-stepper-link-qr-code-title | HaapiStepperLinkUI | QR code link figcaption |
.haapi-stepper-link-qr-code-button | HaapiStepperLinkUI | QR code link expand button |
.haapi-stepper-link-qr-code-dialog | HaapiStepperQrCodeLinkDialog | Fullscreen QR code dialog |
.haapi-stepper-link-qr-code-dialog-close-button | HaapiStepperQrCodeLinkDialog | Button wrapping the expanded QR code image; closes the dialog when clicked |
.haapi-stepper-link-qr-code-dialog-image | HaapiStepperQrCodeLinkDialog | Fullscreen QR code dialog image |
.haapi-stepper-actions | HaapiStepperActionsUI | Actions container |
.haapi-stepper-heading | HaapiStepperMessagesUI | Heading messages |
.haapi-stepper-userName | HaapiStepperMessagesUI | User name display |
.haapi-stepper-userCode | HaapiStepperMessagesUI | User code display (e.g. recovery codes) |
.haapi-stepper-polling-progress | HaapiStepperClientOperationUI | Remaining polling time indicator (e.g. recovery codes) |
.haapi-stepper-error-boundary-fallback | DefaultErrorFallback | Error boundary fallback container |
.haapi-validation-errors-container | HaapiStepperFormValidationErrorInputWrapper | Wrapper around a form field that has validation errors. Receives the .has-errors modifier class while errors are visible |
.haapi-validation-errors | HaapiStepperFormValidationErrorInputWrapper | Inner container that holds the list of validation error messages |
.haapi-validation-error | HaapiStepperFormValidationErrorInputWrapper | A single validation error entry (also gets the utility classes .red .py1) |
.haapi-validation-error-description | HaapiStepperFormValidationErrorInputWrapper | Validation error message text |
Customize with render interceptors
Render interceptors are the programmatic way to customize the default step UI elements — loader, error, step, actions (form, client operation, selector), links, messages, and form fields.
Each is a function that receives the HaapiStepper API data for the target UI element (currentStep, loading, error, nextStep…) and returns either a React element to replace the default UI element, the API data to render the default UI element, or null to skip the element from being rendered:
💡 Design pattern note: always return or pass through the API data.
- To override: return your custom element.
- To delegate to the default renderer: return the API data (
{ currentStep, history, loading, error, nextStep }), optionally modified.- To remove an element: return
null.
Customize with UI composition
The declarative path to build UIs from scratch. Use it for what the API doesn't expose as elements — grouping (fieldsets/tabs), cross-element layouts, inserting your own elements, and behaviour customizations (tabs, multi-step wizards). Best for layout and complex customizations.
Each HAAPI entity has a corresponding UI component (HaapiStepperActionsUI, HaapiStepperMessagesUI, HaapiStepperLinksUI…). HaapiStepper still runs the flow:
Mixed — combine the default with your own UI
Render interceptors and UI composition aren't exclusive — mix them wherever it helps. For
example, return UI building blocks from a render interceptor to restructure part of the
default UI while keeping everything else: a form render interceptor that re-lays-out the same
fields, a step interceptor that swaps one step's UI, or the headless HaapiStepper driving a
mix of building blocks, plain HTML and third-party components.