> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Customization Basics

> Learn how to customize the appearance and behavior of the Para Modal to match your application's design.

export const Link = ({href, label, newTab = false}) => {
  const [isHovered, setIsHovered] = useState(false);
  return <a href={href} target={newTab ? '_blank' : '_self'} rel={newTab ? 'noopener noreferrer' : undefined} className="not-prose inline-block relative text-black font-semibold cursor-pointer border-b-0 no-underline" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      {label}
      <span className={`absolute left-0 bottom-0 w-full rounded-sm bg-gradient-to-r from-orange-600 to-purple-600 transition-all duration-300 ${isHovered ? 'h-0.5' : 'h-px'}`} />
    </a>;
};

export const MethodDocs = ({name, description, parameters = [], returns, deprecated = false, since = null, async = false, static: isStatic = false, tag = null, defaultExpanded = false, preventCollapse = false, id = 'method'}) => {
  const [isExpanded, setIsExpanded] = useState(defaultExpanded || preventCollapse);
  const [isHovered, setIsHovered] = useState(false);
  const [isCopied, setIsCopied] = useState(false);
  const [hoveredParam, setHoveredParam] = useState(null);
  const [hoveredReturn, setHoveredReturn] = useState(false);
  const parseMethodName = fullName => {
    const match = fullName.match(/^([^(]+)(\()([^)]*)(\))$/);
    if (match) {
      return {
        name: match[1],
        openParen: match[2],
        params: match[3],
        closeParen: match[4]
      };
    }
    return {
      name: fullName,
      openParen: '',
      params: '',
      closeParen: ''
    };
  };
  const methodParts = parseMethodName(name);
  const handleCopy = e => {
    e.stopPropagation();
    navigator.clipboard.writeText(name);
    setIsCopied(true);
    setTimeout(() => setIsCopied(false), 2000);
  };
  return <div className={`not-prose rounded-2xl border border-gray-200 overflow-hidden transition-colors duration-200 mb-6 ${isHovered && !preventCollapse ? 'bg-gray-50' : 'bg-white'}`} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)}>
      <button onClick={() => !preventCollapse && setIsExpanded(!isExpanded)} className={`w-full bg-transparent p-6 border-none text-left ${preventCollapse ? 'cursor-default' : 'cursor-pointer'}`}>
        <div className="flex items-start justify-between gap-4">
          <div className="flex-1 flex flex-col gap-2">
            <div className="flex items-center gap-3 flex-wrap">
              <div className="flex items-center gap-2">
                {async && <span className="px-1.5 py-0.5 text-[0.625rem] font-medium bg-purple-200 text-purple-800 rounded-lg">
                    async
                  </span>}
                {isStatic && <span className="px-1.5 py-0.5 text-[0.625rem] font-medium bg-violet-200 text-violet-900 rounded-lg">
                    static
                  </span>}
                {tag && <span className="px-1.5 py-0.5 text-[0.625rem] font-medium bg-teal-200 text-teal-800 rounded-lg">
                    {tag}
                  </span>}
              </div>

              <code className="text-lg font-mono font-semibold text-gray-900">
                <span>{methodParts.name}</span>
                <span className="text-gray-500 font-normal">{methodParts.openParen}</span>
                <span className="text-blue-600 font-normal">{methodParts.params}</span>
                <span className="text-gray-500 font-normal">{methodParts.closeParen}</span>
              </code>

              {deprecated && <span className="px-1.5 py-0.5 text-[0.625rem] font-medium bg-red-100 text-red-800 rounded-lg flex items-center gap-0.5">
                  ⚠ Deprecated
                </span>}
              {since && <span className="px-1.5 py-0.5 text-[0.625rem] font-medium bg-blue-100 text-blue-800 rounded-lg">
                  Since v{since}
                </span>}
            </div>

            <p className="text-sm text-gray-600 leading-6 m-0">
              {description}
            </p>
          </div>

          <div className="flex items-center gap-2 flex-shrink-0">
            <button onClick={handleCopy} className="p-2 bg-transparent border-none rounded-md cursor-pointer transition-colors duration-200 text-gray-500 hover:bg-gray-100" title="Copy method signature">
              {isCopied ? <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#16a34a" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <polyline points="20 6 9 17 4 12"></polyline>
                </svg> : <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                  <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                </svg>}
            </button>

            {!preventCollapse && <span className="text-gray-400">
                {isExpanded ? <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <polyline points="18 15 12 9 6 15"></polyline>
                  </svg> : <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                    <polyline points="6 9 12 15 18 9"></polyline>
                  </svg>}
              </span>}
          </div>
        </div>
      </button>

      <div className={`overflow-hidden transition-all duration-300 ease-in-out px-6 border-t border-gray-200 ${isExpanded ? 'max-h-[2000px] opacity-100 pb-6' : 'max-h-0 opacity-0 pb-0'}`}>
        {parameters.length > 0 && <div className="pt-6">
            <div className="flex items-center gap-2 mb-3">
              <h3 className="text-sm font-semibold text-gray-700 uppercase tracking-wider m-0">
                Parameters
              </h3>
              <span className="text-xs text-gray-500">({parameters.length})</span>
            </div>
            <div>
              {parameters.map((param, index) => <div key={index} className={`pl-4 border-l-2 transition-colors duration-200 ${hoveredParam === index ? 'border-gray-300' : 'border-gray-200'} ${index < parameters.length - 1 ? 'mb-3' : ''}`} onMouseEnter={() => setHoveredParam(index)} onMouseLeave={() => setHoveredParam(null)}>
                  <div className="flex items-baseline gap-2 mb-1 flex-wrap">
                    <code className="font-mono text-sm font-medium text-gray-900">
                      {param.name}
                    </code>
                    <span className="text-sm text-gray-500">:</span>
                    {param.typeLink ? <a href={param.typeLink} className="no-underline">
                        <code className="font-mono text-sm text-blue-600 bg-transparent px-1 py-0.5 rounded-md cursor-pointer transition-all duration-200 hover:bg-gray-100 hover:text-blue-700">
                          {param.type}
                        </code>
                      </a> : <code className="font-mono text-sm text-blue-600 bg-transparent px-1 py-0.5 rounded-md">
                        {param.type}
                      </code>}
                    {param.required && <span className="px-1.5 py-0.5 text-[0.625rem] font-medium bg-yellow-100 text-yellow-800 rounded-lg">
                        Required
                      </span>}
                    {param.optional && <span className="px-1.5 py-0.5 text-[0.625rem] font-medium bg-gray-100 text-gray-600 rounded-lg">
                        Optional
                      </span>}
                  </div>
                  {param.description && <p className="text-sm text-gray-600 mt-1 mb-0">
                      {param.description}
                    </p>}
                  {param.defaultValue !== undefined && <p className="text-sm text-gray-500 mt-1">
                      Default: <code className="font-mono text-[0.625rem] bg-gray-100 px-1.5 py-0.5 rounded-lg">{param.defaultValue}</code>
                    </p>}
                </div>)}
            </div>
          </div>}

        {returns && <div className={`${parameters.length > 0 ? 'mt-6' : 'pt-6'}`}>
            <h3 className="text-sm font-semibold text-gray-700 uppercase tracking-wider m-0 mb-3">
              Returns
            </h3>
            <div className={`pl-4 border-l-2 transition-colors duration-200 ${hoveredReturn ? 'border-gray-300' : 'border-gray-200'}`} onMouseEnter={() => setHoveredReturn(true)} onMouseLeave={() => setHoveredReturn(false)}>
              <div className="flex items-baseline gap-2 mb-1">
                {returns.typeLink ? <a href={returns.typeLink} className="no-underline">
                    <code className="font-mono text-sm text-blue-600 bg-transparent px-1 py-0.5 rounded cursor-pointer transition-all duration-200 hover:bg-gray-100 hover:text-blue-700">
                      {returns.type}
                    </code>
                  </a> : <code className="font-mono text-sm text-blue-600 bg-transparent px-1 py-0.5 rounded">
                    {returns.type}
                  </code>}
              </div>
              {returns.description && <p className="text-sm text-gray-600 mt-1 mb-0">
                  {returns.description}
                </p>}
            </div>
          </div>}
      </div>
    </div>;
};

The `paraModalConfig` prop passed to `ParaProvider` controls the modal's runtime behavior and accepts a number of customization options.

<Warning>
  In v3, the **partner record** is the source of truth for configuration (auth methods, theme, 2FA, guest mode, layout, branding). The matching `paraModalConfig` props below — such as `oAuthMethods`, `theme`, `twoFactorAuthEnabled`, `isGuestModeEnabled`, `authLayout`, `logo` — are **deprecated** and act only as a lowest-priority fallback. Configure these in the [Developer Portal](https://developer.getpara.com), and read [How Configuration Works](/v3/react/guides/customization/configuration) for the supported in-code override (`configOverrides`). The props that remain code-only are runtime/behavior props like `currentStepOverride`, `defaultAuthIdentifier`, and `onClose`.
</Warning>

<Frame>
  <img src="https://mintcdn.com/getpara/8_K4LmkBd5jFZ3IC/images/v3/para-customize-callout.png?fit=max&auto=format&n=8_K4LmkBd5jFZ3IC&q=85&s=7c9a4cf542b6630ae32331ff57c54a92" alt="Para Modal Customization" width="3704" height="2596" data-path="images/v3/para-customize-callout.png" />
</Frame>

## Basic Setup

Pass the `paraModalConfig` object to your `ParaProvider` to customize the modal:

```tsx theme={null}
<ParaProvider
  paraClientConfig={{
    apiKey: process.env.REACT_APP_PARA_API_KEY || "",
  }}
  config={{
    appName: "Your App Name"
  }}
  paraModalConfig={{
    logo: "https://yourdomain.com/logo.png",
    theme: {
      foregroundColor: "#007AFF",
      backgroundColor: "#FFFFFF"
    },
    // ... other customization options
  }}
>
  {children}
</ParaProvider>
```

## Configuration Options

A full list of available configuration options for the `paraModalConfig` prop available on the `ParaProvider` component:

<MethodDocs
  name="paraModalConfig"
  description="Complete configuration object for customizing the Para Modal appearance and behavior"
  defaultExpanded={false}
  parameters={[
{
  name: "para",
  type: "ParaWeb",
  required: false,
  description: "Your ParaWeb instance (automatically provided when using ParaProvider)"
},
{
  name: "isOpen",
  type: "boolean",
  required: false,
  description: "Whether the modal is open (managed automatically by useModal hook)"
},
{
  name: "logo",
  type: "string",
  required: false,
  description: "Logo URL to display throughout the modal. Recommended dimensions: 372px x 160px"
},
{
  name: "theme",
  type: "ParaTheme",
  required: false,
  description: "Theme configuration for colors, fonts, and styling. See the Style the Modal guide for details."
},
{
  name: "twoFactorAuthEnabled",
  type: "boolean",
  required: false,
  default: "false",
  description: "Enable two-factor authentication steps in the modal flow"
},
{
  name: "recoverySecretStepEnabled",
  type: "boolean",
  required: false,
  default: "false",
  description: "Show wallet recovery option to users during setup"
},
{
  name: "oAuthMethods",
  type: "TOAuthMethod[]",
  required: false,
  description: "Array of OAuth providers to display. Available: 'GOOGLE', 'TWITTER', 'APPLE', 'DISCORD', 'FACEBOOK', 'FARCASTER', 'TELEGRAM'"
},
{
  name: "disableEmailLogin",
  type: "boolean",
  required: false,
  default: "false",
  description: "Disable email-based authentication"
},
{
  name: "disablePhoneLogin",
  type: "boolean",
  required: false,
  default: "false",
  description: "Disable phone-based authentication"
},
{
  name: "defaultAuthIdentifier",
  type: "string",
  required: false,
  description: "Pre-populate the auth input with an email or phone number (format: +15555555555)"
},
{
  name: "authLayout",
  type: "TAuthLayout[]",
  required: false,
  default: "[AuthLayout.AUTH_FULL, AuthLayout.EXTERNAL_FULL]",
  description: "Configure the layout and order of authentication components"
},
{
  name: "currentStepOverride",
  type: "ModalStepProp",
  required: false,
  description: "Override the initial step shown when modal opens"
},
{
  name: "hideWallets",
  type: "boolean",
  required: false,
  default: "false",
  description: "Hide wallet-related information and terminology"
},
{
  name: "isGuestModeEnabled",
  type: "boolean",
  required: false,
  default: "false",
  description: "Enable guest login with provisional wallets"
},
{
  name: "onRampTestMode",
  type: "boolean",
  required: false,
  default: "false",
  description: "Run on-ramp providers in test mode"
},
{
  name: "bareModal",
  type: "boolean",
  required: false,
  default: "false",
  description: "Renders the modal inline without a dialog overlay or portal, suitable for embedding directly in your app's layout. The modal is always visible, the close button is hidden, and the auth view resets to the main screen when disconnected."
},
{
  name: "className",
  type: "string",
  required: false,
  description: "Additional CSS class name for the modal"
},
{
  name: "supportedAccountLinks",
  type: "SupportedAccountLinks",
  required: false,
  description: "Configure which external accounts users can link to their Para account"
},
{
  name: "balances",
  type: "BalancesConfig",
  required: false,
  description: "Configuration for the profile balances displayed in the Para Modal"
},
{
  name: "disableAddFundsPrompt",
  type: "boolean",
  required: false,
  default: "false",
  description: "Hide the Add Funds prompt shown on the wallet creation screen after signup. Does not affect the Add Funds button in the main account view."
},
{
  name: "onWalletCreated",
  type: "(_: { recoverySecret?: string }) => void",
  required: false,
  description: "Callback called when new wallets are created during the authentication process. Useful for storing the recovery secret."
},
{
  name: "onClose",
  type: "() => void",
  required: false,
  description: "Callback fired when the modal is closed"
}
]}
/>

## Complete Example

Here's a comprehensive example showcasing multiple configuration options:

```tsx theme={null}
<ParaProvider
  paraClientConfig={{
    apiKey: process.env.REACT_APP_PARA_API_KEY || "",
  }}
  config={{
    appName: "Your App Name"
  }}
  paraModalConfig={{
    // Runtime / behavior props — these stay in code:
    defaultAuthIdentifier: "user@example.com",
    recoverySecretStepEnabled: true,
    currentStepOverride: "AUTH_MAIN",
    onRampTestMode: false,
    onClose: () => {
      console.log('Modal closed');
    },

    // ⚠️ DEPRECATED — these are now configured on the partner record
    // (Developer Portal), or via `configOverrides` on ParaProvider. Shown here
    // only to map the old prop names. See:
    // /v3/react/guides/customization/configuration
    logo: "https://yourdomain.com/logo.png",
    oAuthMethods: ["GOOGLE", "TWITTER", "DISCORD"],
    disablePhoneLogin: false,
    disableEmailLogin: false,
    authLayout: ["AUTH:FULL", "EXTERNAL:CONDENSED"],
    twoFactorAuthEnabled: true,
    isGuestModeEnabled: false,
    theme: {
      foregroundColor: "#007AFF",
      backgroundColor: "#FFFFFF",
      mode: "light",
      borderRadius: "md",
      font: "Inter, sans-serif",
      foregroundMixRatio: 0.04
    },
    supportedAccountLinks: ["EMAIL", "PHONE", "GOOGLE", "TWITTER", "EXTERNAL_WALLET"]
  }}
>
  {children}
</ParaProvider>
```

## Modal Designer

Test your modal configuration with our interactive tool:

<Card horizontal title="Modal Designer" imgUrl="/images/v3/general-customize.png" href="https://demo.getpara.com/" description="Interactive tool to preview and test modal configurations in real-time." />

## Next Steps

Explore detailed configuration guides for specific aspects of the modal:

<CardGroup cols={2}>
  <Card title="Configure Authentication" href="/v3/react/guides/customization/developer-portal-authentication" description="Set up OAuth providers, email/phone login, external wallets, 2FA, and display order" />

  <Card title="Style the Modal" href="/v3/react/guides/customization/modal-theming" description="Customize colors, fonts, and visual appearance" />
</CardGroup>
