Customization
We offer many ways to customize the experience of the login and wallet. This includes theming, localization and other settings such as control over the login methods or recommended wallets.
Below you can find all currently available settings:
{
// Identifier of your theme which specifies the css property name
// and html tag, e.g. "anime".
theme?: string;
// A whitelist of origin hostnames, any other domain will abort
// the service initialization. E.g. ["sdk-demo.web3.com"]
allowedDomains: string[];
// In case you want to use custom auth and/or jwt gating,
// we will use either the public key or the jwks endpoint
// to validate your tokens.
publicKey?: string;
jwksUrl?: string;
// Defines the available login methods in specified order
loginMethods?: ("passwordless", "passwordlessToggle", "google", "wallet")[];
// Defines the wallet options for the login and signup screen
// in specified order. For this to show up, "wallet" needs to be
// in the list of loginMethods above.
walletLoginMethods?: ("metamask" | "coinbase" | "okx")[];
// Defines the recommended wallet options in specified order.
recommendedWallets?: ("metamask" | "coinbase" | "okx")[];
// The default language to fallback to when none is matching, e.g. "en"
defaultLanguage?: string;
style?: {
// Select between having the passwordless button inlined inside
// the email input or standalone. Default is inline.
passwordlessButtonVariant?: 'inline' | 'standalone';
// Change the air logo dark and light behaviour to best match the
// partner theme
airLogoTheme?: "default" | "reverse" | "dark_only" | "light_only";
// Show the advanced details section expanded on the transaction screen.
// By default it is collapsed.
transactionDetailsExpanded?: boolean;
}
}
Theming
For custom theming the you can provide us following CSS custom properties below with your partner name
specified in the config above as theme
.
:root {
--name-air-text-primary-color: #002536;
--name-air-text-secondary-color: #5C5F5F;
--name-air-text-placeholder-color: #8E9191;
--name-air-text-disabled-color: #747878;
--name-air-text-inverse-color: #FFFFFF;
--name-air-text-on-color: #002536;
--name-air-button-primary-color: #CCE8EA;
--name-air-button-primary-hover-color: #DAF6F9;
--name-air-button-secondary-color: #C3B6F8;
--name-air-button-secondary-hover-color: #E2D8FF;
--name-air-button-disabled-color: #E0E3E3;
--name-air-button-outlined-color: #6F797A;
--name-air-button-outlined-hover-color: #FFFFFF;
--name-air-button-outlined-secondary-color: #3F4849;
--name-air-button-outlined-secondary-hover-color: #C8D2D4;
--name-air-border-color: #BFC8CA;
--name-air-border-focus-color: #FFFFFF;
--name-air-link-color: #00696F;
--name-air-text-button-color: #00696F;
--name-air-icon-primary-color: #002536;
--name-air-icon-secondary-color: #6F797B;
--name-air-icon-hover-color: #80D4DB;
--name-air-icon-disabled-color: #747878;
--name-air-status-success-color: #00C773;
--name-air-status-error-color: #FF4949;
--name-air-status-pending-color: #F99247;
--name-air-status-warning-color: #E7B400;
--name-air-surface-color: #F5FAFC;
--name-air-surface-dim-color: #343A3B;
--name-air-overlay-color: #00000050;
--name-air-container-primary-color: #F4F4F4;
--name-air-container-secondary-color: #FFFFFF;
--name-air-decorative-color: #9371F1;
--name-air-secondary-5-color: #E8E1FD;
--name-air-background-color: var(--name-air-container-primary-color);
--name-air-logo: url('https://static.air3.com/assets/name-logo.png');
}
@media (prefers-color-scheme: dark) {
:root {
--name-air-text-primary-color: #ffffff;
--name-air-text-secondary-color: #b0b0b0;
--name-air-text-placeholder-color: #767676;
--name-air-text-disabled-color: #ffffff25;
--name-air-text-inverse-color: #000000;
--name-air-text-on-color: #ffffff;
--name-air-button-primary-color: #00bec9;
--name-air-button-primary-hover-color: #80d4db;
--name-air-button-secondary-color: #8E74FF;
--name-air-button-secondary-hover-color: #A793FF;
--name-air-button-disabled-color: #535353;
--name-air-button-outlined-color: #ffffff;
--name-air-button-outlined-hover-color: #2a3233;
--name-air-button-outlined-secondary-color: #3F4849;
--name-air-button-outlined-secondary-hover-color: #2A3233;
--name-air-border-color: #3f4849;
--name-air-border-focus-color: #00bec9;
--name-air-link-color: #00bec9;
--name-air-text-button-color: #00bec9;
--name-air-icon-primary-color: #ffffff;
--name-air-icon-secondary-color: #b0b0b0;
--name-air-icon-hover-color: #80d4db;
--name-air-icon-disabled-color: #ffffff25;
--name-air-status-success-color: #74ffcd;
--name-air-status-error-color: #ff4949;
--name-air-status-pending-color: #f99247;
--name-air-status-warning-color: #E7B400;
--name-air-surface-color: #1a2121;
--name-air-surface-dim-color: #343a3b;
--name-air-overlay-color: #00000050;
--name-air-container-primary-color: #252b2c;
--name-air-container-secondary-color: #161d1d;
--name-air-decorative-color: #d7e3ff;
--name-air-secondary-5-color: #FFFFFF;
--name-air-background-color: var(--name-air-container-primary-color);
--name-air-logo: url('https://static.air3.com/assets/name-logo-light.png');
}
}
}
Localization
Currently we only offer English out of the box, but you can change the English wording or add additional languages. Our SDK will pick the language based on the user's browser language. If it does not match any of our available language files, we will fallback to English or the language you have specified as default language.
Below you can find the two language files which can be adjusted or need to be provided for any additional language.
Login:
{
"login": {
"agree": "By logging in, you agree to our {termsOfUse} & {privacyPolicy}",
"termsOfUse": "Terms of Use",
"privacyPolicy": "Privacy Policy",
"termsOfUseUrl": "https://www.mocaverse.xyz/terms-of-use",
"privacyPolicyUrl": "https://moca.network/privacy_policy.pdf",
"captcha": {
"title": "Security Check Required",
"description": "Please complete the security check below to continue",
"verifying": "Verifying security check..."
},
"showSecondaryLogin": {
"text": "Text Placeholder",
"button": "Button Placeholder"
},
"loading": {
"google": "Verify your Google account"
},
"emailVerification": {
"loginToAirId": "You can also log into your Air ID with your email address provided below",
"provideEmail": "Provide your email address"
},
"footer": "Powered by",
"google": {
"button": "Continue with Google",
"error": "Google login failed. Please try again or use another login method."
},
"or": "or",
"passkey": {
"add": "Add Passkey",
"authenticating": "Authenticating...",
"button": "Continue with Passkey",
"error": "Failed to login with passkey. Please try again or use another login method.",
"notSupportedError": "Passkey login failed. Please try again or use another login method.",
"register": "Register passkey",
"skip": "Skip for now"
},
"passkeySetting": {
"title": "Passkey Setting",
"register": "Register New Passkey",
"registering": "Registering...",
"notSupportedError": "Your browser does not support passkeys.",
"notRegistered": " No passkeys registered yet.",
"totalPasskeys": "Total passkeys: {0}",
"next": "Next",
"go": "Go",
"ofPages": "of {0}",
"prev": "Prev",
"delete": "Delete",
"deleting": "Deleting...",
"lastUsed": "Last used: {0}",
"created": "Created: {0}",
"failedToRegister": "Failed to register passkey. Please try again.",
"failedToDelete": "Failed to delete passkey. Please try again.",
"failedToLoad": "Failed to load passkeys. Please try again.",
"cancelRegister": "Passkey registration was cancelled."
},
"passwordless": {
"button": "Continue",
"invalidError": "Invalid email address",
"placeholder": "Enter email address",
"requiredEmailError": "*Empty email"
},
"passwordlessOtp": {
"enterEmail": "Please enter your email to continue",
"title": "Enter email verification code",
"description": "Enter the code we sent to {0}",
"resendCountdown": "Resend code ( {0}s )",
"resend": "Resend code",
"invalidCode": "Invalid code, please try again",
"expiredCode": "Code expired",
"invalidFormat": "Code should be numeric only",
"unknownError": "Unknown error",
"tooManyRequests": "Oops! You made too many requests, please retry later.",
"maxAttemptsExceeded": "Oops! Too many attempts, please retry later.",
"captchaTokenVerificationFailed": "Captcha token verification failed. Please try again later.",
"captchaTokenInvalid": "The security check could not be completed. Please refresh the page and try again.",
"captchaSecretMissing": "Security verification is temporarily unavailable. Please contact support.",
"captchaTokenMissing": "Please complete the security check before proceeding.",
"securityCheckRequired": "Please complete the security check before proceeding",
"securityCheckFailed": "Security verification failed. Please try again",
"checkSpam": "Check your spam folder if you can't find it in your inbox.",
"walletAlreadyLinked": "The email address you provided is already linked to another wallet.",
"walletLinkedOtherAccount": "The wallet you provided is already linked to another account.",
"emailLinkedOtherAccount": "The email address is already used by another user."
},
"title": "",
"wallet": {
"button": "Continue with a wallet",
"checkWallet": "Check your {0}",
"connectedWallet": "Connected with {0}",
"confirmConnection": "Confirm connection in your wallet",
"failedToConnect": "Failed to connect with {0}",
"signMessage": "Sign to verify you own this wallet",
"tryAgain": "Try again",
"selectWallet": "Select a Wallet",
"installed": "Installed",
"recommended": "Recommended",
"error": "Wallet login failed. Please try again or use another login method."
},
"error": {
"rateLimitError": "Too many requests have been sent to us. Please try again later."
}
},
"linking": {
"landing": {
"title": "wants to connect",
"subTitle": "Would like to",
"connectWith": "Connect with {0}",
"description": "Track your in game activities in order to reward you with Realm Points and other benefits, all while accruing reputation.",
"reject": "Reject"
},
"loading": {
"title": "Linking with {0}"
},
"result": {
"title": "You have been linked to your",
"done": "Done"
},
"error": {
"title": "You have already been linked to a",
"subTitle": "An error occurred while linking your account",
"message": "To fix this issue, open a support ticket on Discord and share ticket ID",
"done": "Done"
}
}
}
Wallet Services:
{
"signMessage": {
"loading": "Loading...",
"title": "Signature Request",
"description": "Only sign this message if you fully understand the content and trust the requesting site.",
"messageTitle": "Message to sign:",
"noFeeRequired": "This action does not cost any fee.",
"button": {
"confirm": "Confirm",
"cancel": "Cancel"
},
"windowBlocked": "Window blocked, please allow popups and try again"
},
"claim": {
"claimId": {
"loading": "Loading...",
"chooseUsername": "Choose a username for your {{node}} ID",
"chooseUsernameDesc": "This username will be used across the ecosystem and cannot be changed later on.",
"claimIdButton": "Claim {{node}} ID",
"createId": "Creating {{node}} ID",
"usernameInputPlaceholder": "Username",
"usernameRequirement1": "Only made of letters or numbers",
"usernameRequirement2": "Between {{minLength}} to {{maxLength}} characters",
"usernameRequirements": "Your username must be:"
},
"claimIdResult": {
"claimIdSuccess": "Successfully created your ID",
"done": "Done",
"airAccountAddress": "Your Air Account Address",
"viewResult": "View On {{blockExplorerName}}"
},
"claimIdRetry": {
"almostThere": "Almost there",
"claimIdRetryReason": "There might have been a network interruption while minting your {{node}} ID, click below to try again.",
"retry": "Retry"
},
"error":{
"nameAlreadyExists": "Air id {{name}} already exists",
"alreadyHasAirId":"User already has an air id ({{name}})",
"nameProfanity":"Profanity detected in name",
"nameReserved":"Name is reserved",
"multipleAirIds":"Multiple air ids found for {{name}}",
"failedToMint":"Failed to mint {{name}}.{{node}}",
"failedToReserveName": "Failed to reserve name"
}
},
"signTransaction": {
"loading": "Loading...",
"warning": " Once confirmed, the transaction cannot be canceled.",
"cancel": "Cancel",
"confirm": "Confirm",
"confirmTransaction": "Review this transaction carefully before proceeding.",
"reviewBeforeProceeding": "Make sure you trust this request before proceeding.",
"title": {
"p2pSendFunds": "Confirm to {{action}} {{amount}} {{tickerSymbol}}",
"confirmTransactionWithIntent": "Confirm your {{intent}} {{target}}",
"confirmYourTransaction": "Confirm your transaction"
},
"intent": {
"send": "Send to",
"swap": "Swap on",
"stake": "Stake on",
"unstake": "Unstake from",
"claim": "Claim on",
"approve": "Approval on",
"mint": "Mint on",
"burn": "Burn on",
"bridge": "Bridge on",
"withdraw": "Withdraw from",
"deposit": "Deposit to",
"transfer": "Transfer to",
"redeem": "Redeem on",
"transaction": "Transaction on"
},
"preview": {
"title": "Preview transaction details:",
"hexData": "Hex data",
"time": "Time",
"network": "Network",
"function": "Function",
"sendingAmount": "Sending amount",
"gasFee": "Gas fee",
"total": "Total",
"networkFee": "Network Fee",
"Free": "Free",
"contract": "Contract",
"hideAdvancedDetail": "Hide advanced details",
"viewAdvancedDetail": "View advanced details"
},
"requestedBy": "Requested by",
"analysis": {
"analyzing": "Analyzing transaction...",
"nativeTransfer": "Native Token Transfer",
"contractInteraction": "Contract Interaction",
"contractDeployment": "Contract Deployment",
"function": "Function"
},
"windowBlocked": "Window blocked, please allow popups and try again",
"retry":{
"title": "Allow pop up windows",
"description": "Pop-up blocked. Click ‘Retry’ to allow and continue"
}
},
"error": {
"back": "Back",
"oops": "Oops",
"pleaseTryAgain": "Please try again",
"rateLimitError": "Too many requests have been sent to us. Please try again later.",
"unexpectedError": "An unexpected error occurred. Please try again.",
"retry": "Retry"
},
"footer": "Powered by",
"mfa": {
"setup": {
"verify": {
"title": "Verifying with passkey"
},
"success": {
"title": "Your passkey has been set",
"subTitle": "You can use this passkey to log in across your device",
"added": "Added",
"done": "Done"
},
"passkey": {
"title": " Set up passkey",
"continue": "Continue",
"benefit1Title": "Fast and convenient",
"benefit1Desc": "Seamlessly verify yourself with your face, fingerprint, PIN or hardware key in seconds",
"benefit2Title": "Works on all of your device",
"benefit2Desc": "Your passkeys can be used across synced device",
"protectDesc": "Your passkey helps protect your AIR Account, so make sure it’s stored somewhere safe and accessible by only you"
},
"landing": {
"title": "Set up 2FA to secure your transactions",
"subTitle": "You need to set up a 2-factor authentication (2FA) before sending or receiving funds.",
"emailVerification": "Email verification",
"passkey": "Passkey",
"setUp": "Set up"
},
"error": {
"tryAgain": "Try again",
"failToSetup": "Failed to set up a passkey",
"timeout": "Passkey set up request time out",
"windowBlocked": "Window blocked, please click setup again"
}
},
"required": {
"verify": {
"title": "Verifying with passkey",
"subTitle": "Use the following passkey to continue",
"airAccount": "AIR account",
"keychainDesc": "for Safari browsers and all iOS devices",
"chromeDesc": "for Chrome browsers and all Android devices"
},
"success": {
"title": "Transaction complete"
},
"error": {
"failedToUse": "Failed to use passkey"
}
},
"authenticator":{
"icloudKeychain": "iCloud Keychain",
"googlePasswordManager": "Google Password Manager",
"edge": "Microsoft Edge"
}
},
"batchTransaction": {
"transaction": "Batch Transaction",
"transactions": "Batch Transaction Count: {{count}}",
"callData": "Call Data",
"loading": "Loading transaction details...",
"confirmYourTransaction": "Confirm your Batch transaction",
"title": "Error while simulating transaction"
},
"common": {
"close": "Close"
}
}