diff --git a/packages/wallets/docs/examples/FlowProvider/AccountFlow/AccountFlow.tsx b/packages/wallets/docs/examples/FlowProvider/AccountFlow/AccountFlow.tsx
new file mode 100644
index 000000000000..71aa476b9ee0
--- /dev/null
+++ b/packages/wallets/docs/examples/FlowProvider/AccountFlow/AccountFlow.tsx
@@ -0,0 +1,118 @@
+import React from 'react';
+import { ModalStepWrapper } from '../../../../src/components/Base/ModalStepWrapper';
+import { FlowProvider, TFlowProviderContext, useFlow } from '../../../../src/components/FlowProvider';
+import { useModal } from '../../../../src/components/ModalProvider';
+import { MT5AccountType } from '../../../../src/features/cfd/screens/MT5AccountType';
+import VerificationFlow from './VerificationFlow';
+
+const PasswordScreen = () => {
+ return (
+
+ Password Screen in Account Flow
+
+ );
+};
+
+const ScreenB = () => {
+ const { formValues, setFormValues } = useFlow();
+ return (
+
+
Screen B
+ setFormValues('testb', e.target.value)}
+ style={{ border: '1px solid black', padding: '4px', width: '100%' }}
+ type='text'
+ value={formValues.testb}
+ />
+ setFormValues('testa', e.target.value)}
+ style={{ border: '1px solid black', padding: '4px', width: '100%' }}
+ type='text'
+ value={formValues.testa}
+ />
+
+ );
+};
+
+const ScreenA = () => {
+ const { formValues, setFormValues } = useFlow();
+
+ return (
+
+ setFormValues('testa', e.target.value)}
+ style={{ border: '1px solid black', padding: '4px', width: '100%' }}
+ type='text'
+ value={formValues.testa}
+ />
+
+ );
+};
+
+const JurisdictionScreen = () => {
+ return (
+
+
Jurisdiction Screen
+
+ );
+};
+
+const screens = {
+ aScreen: ,
+ bScreen: ,
+ JurisdictionScreen: ,
+ passwordScreen: ,
+ selectAccountTypeScreen: marketType} selectedMarketType='all' />,
+};
+
+const AccountFlow = () => {
+ const { show } = useModal();
+ const nextFlowHandler = ({
+ currentScreenId,
+ switchScreen,
+ switchNextScreen,
+ }: TFlowProviderContext) => {
+ switch (currentScreenId) {
+ case 'bScreen':
+ show();
+ break;
+ case 'passwordScreen':
+ switchScreen('bScreen');
+ break;
+ default:
+ switchNextScreen();
+ }
+ };
+
+ return (
+
+ {context => {
+ return (
+ (
+
+ )}
+ title='Account Flow'
+ >
+ {context.WalletScreen}
+
+ );
+ }}
+
+ );
+};
+
+export default AccountFlow;
diff --git a/packages/wallets/docs/examples/FlowProvider/AccountFlow/VerificationFlow.tsx b/packages/wallets/docs/examples/FlowProvider/AccountFlow/VerificationFlow.tsx
new file mode 100644
index 000000000000..76401f2f4972
--- /dev/null
+++ b/packages/wallets/docs/examples/FlowProvider/AccountFlow/VerificationFlow.tsx
@@ -0,0 +1,116 @@
+import React from 'react';
+import { ModalWrapper } from '../../../../src/components/Base';
+import { ModalStepWrapper } from '../../../../src/components/Base/ModalStepWrapper';
+import { FlowProvider, TFlowProviderContext, useFlow } from '../../../../src/components/FlowProvider';
+import { useModal } from '../../../../src/components/ModalProvider';
+
+const PasswordScreen = () => {
+ return (
+
+ Password Screen in Verification Flow
+
+ );
+};
+
+const ScreenB = () => {
+ const { formValues, setFormValues } = useFlow();
+ return (
+
+
Screen X in Verification Flow
+ setFormValues('testb', e.target.value)}
+ style={{ border: '1px solid black', padding: '4px', width: '100%' }}
+ type='text'
+ value={formValues.testb}
+ />
+ setFormValues('testa', e.target.value)}
+ style={{ border: '1px solid black', padding: '4px', width: '100%' }}
+ type='text'
+ value={formValues.testa}
+ />
+
+ );
+};
+
+const ScreenA = () => {
+ const { formValues, setFormValues } = useFlow();
+
+ return (
+
+ setFormValues('testa', e.target.value)}
+ style={{ border: '1px solid black', padding: '4px', width: '100%' }}
+ type='text'
+ value={formValues.testa}
+ />
+
+ );
+};
+
+const SuccessModal = () => {
+ return (
+
+
+
SUCCESS MODAL!
+
+
+ );
+};
+
+const screens = {
+ aScreen: ,
+ bScreen: ,
+ passwordScreen: ,
+};
+
+const VerificationFlow = () => {
+ const { show } = useModal();
+ const nextFlowHandler = ({ currentScreenId, switchNextScreen }: TFlowProviderContext) => {
+ switch (currentScreenId) {
+ case 'bScreen':
+ show();
+ break;
+ default:
+ switchNextScreen();
+ }
+ };
+
+ return (
+
+ {context => {
+ return (
+ (
+
+ )}
+ title='Verification Flow'
+ >
+ {context.WalletScreen}
+
+ );
+ }}
+
+ );
+};
+
+export default VerificationFlow;
diff --git a/packages/wallets/docs/examples/FlowProvider/AccountFlow/index.ts b/packages/wallets/docs/examples/FlowProvider/AccountFlow/index.ts
new file mode 100644
index 000000000000..be5aa3dc896b
--- /dev/null
+++ b/packages/wallets/docs/examples/FlowProvider/AccountFlow/index.ts
@@ -0,0 +1 @@
+export { default as AccountFlow } from './AccountFlow';
diff --git a/packages/wallets/src/components/FlowProvider/FlowProvider.tsx b/packages/wallets/src/components/FlowProvider/FlowProvider.tsx
new file mode 100644
index 000000000000..f0661ad22b0c
--- /dev/null
+++ b/packages/wallets/src/components/FlowProvider/FlowProvider.tsx
@@ -0,0 +1,126 @@
+import React, {
+ createContext,
+ ReactElement,
+ ReactFragment,
+ ReactNode,
+ ReactPortal,
+ useContext,
+ useMemo,
+ useState,
+} from 'react';
+import { Formik, FormikErrors, FormikValues } from 'formik';
+
+export type TFlowProviderContext = {
+ WalletScreen?: ReactNode;
+ currentScreenId: keyof T;
+ formValues: FormikValues;
+ setFormValues: (
+ field: string,
+ value: unknown,
+ shouldValidate?: boolean | undefined
+ ) => Promise | void>;
+ switchNextScreen: () => void;
+ switchScreen: (screenId: keyof T) => void;
+};
+
+type FlowChildren = ReactElement | ReactFragment | ReactPortal;
+
+export type TWalletScreens = {
+ [id: string]: ReactNode;
+};
+
+export type TFlowProviderProps = {
+ children: (context: TFlowProviderContext) => FlowChildren;
+ initialValues: FormikValues;
+ screens: T;
+ screensOrder: (keyof T)[];
+};
+
+const FlowProviderContext = createContext | null>(null);
+
+/**
+ * Hook to use the flow provider's context.
+ *
+ * @returns {TFlowProviderContext} The flow provider's context:
+ * - `currentScreenId`: The current screen's ID being shown
+ * - `switchScreen`: Function which switches the current screen to another screen by their ID
+ * - `switchNextScreen`: Function which switches to the next screen by default. If the current screen is the final screen, it will not do anything.
+ * - `formValues`: The saved form values stored in Formik. By default it will contain the initial values passed in `initialValues` prop in the provider.
+ * - `setFormValues`: Function which allows persistence for a form value, which can be used to persist the form values for a previous screen or for the next screen.
+ * - `WalletScreen`: The rendered screen which is rendered by the FlowProvider.
+ */
+export const useFlow = () => {
+ const flowProviderContext = useContext(FlowProviderContext);
+
+ if (!flowProviderContext) throw new Error('useFlow must be used within a FlowProvider component.');
+
+ return flowProviderContext;
+};
+
+/**
+ * The FlowProvider is responsible for:
+ * - Grouping screens together into a flow
+ * - Managing screen routing through its context `switchScreen` and `switchNextScreen`
+ * - Ensuring screen order is maintained through the `screensOrder` prop
+ * - Persisting form values in screens through `setFormValues` and restoring them through `formValues`
+ */
+function FlowProvider({
+ children,
+ initialValues,
+ screens,
+ screensOrder,
+}: TFlowProviderProps) {
+ const [currentScreenId, setCurrentScreenId] = useState(screensOrder[0]);
+ const switchScreen = (screenId: keyof T) => {
+ setCurrentScreenId(screenId);
+ };
+
+ const FlowProvider = FlowProviderContext.Provider as React.Provider | null>;
+ const currentScreenIndex = useMemo(() => screensOrder.indexOf(currentScreenId), [currentScreenId, screensOrder]);
+ const isFinalScreen = currentScreenIndex >= screensOrder.length - 1;
+
+ const switchNextScreen = () => {
+ if (!isFinalScreen) {
+ const nextScreenId = screensOrder[currentScreenIndex + 1];
+ switchScreen(nextScreenId);
+ }
+ };
+
+ const currentScreen = useMemo(() => {
+ return screens[currentScreenId];
+ }, [currentScreenId, screens]);
+
+ if (!currentScreenId) return null;
+
+ const context = {
+ currentScreenId,
+ switchNextScreen,
+ switchScreen,
+ WalletScreen: currentScreen,
+ };
+
+ return (
+ // We let the logic of the onSubmit be handled by the flow component
+ undefined}>
+ {({ setFieldValue, values }) => {
+ return (
+
+ {children({
+ ...context,
+ formValues: values,
+ setFormValues: setFieldValue,
+ })}
+
+ );
+ }}
+
+ );
+}
+
+export default FlowProvider;
diff --git a/packages/wallets/src/components/FlowProvider/index.ts b/packages/wallets/src/components/FlowProvider/index.ts
new file mode 100644
index 000000000000..544dc6a0ef1a
--- /dev/null
+++ b/packages/wallets/src/components/FlowProvider/index.ts
@@ -0,0 +1,4 @@
+import FlowProvider, { TFlowProviderContext, useFlow } from './FlowProvider';
+
+export { FlowProvider, useFlow };
+export type { TFlowProviderContext };