Docs

Customize the login text

Change the login's wording, translate it, and label the steps you add to a flow.

The login component looks up every title, description, field label, button and error message by a key: identifier.title, for example, is the title of the screen that asks for the email, "Sign in" in English. It ships dictionaries in English, German and Italian that cover every step of the login flow zitadel setup creates, and picks the visitor's language from the browser.

To change a text, pass locales to ZitadelLogin: for each language, the keys you want to change and their new text. Every key you leave out keeps its built-in text.

<ZitadelLogin locales={{ en: { "identifier.title": "Welcome back" } }} />

Every SDK's ZitadelLogin takes locales (SDKs). On a plain <zitadel-login> element, set it as a JavaScript property: it is not an attribute. German and Italian visitors keep the built-in translation of a text you change only in en (Choose the language).

The example sets identifier.title this way on a live login, which runs against a mock of the flow API in your browser. Change the text, or the language it is set for and shown in:

<zitadel-login>

Loading the example…

string

Find the key for a text

A key starts with the name of the step that shows the text, as your flow file, .zitadel/flows/default-login.json, names it:

TextKey
Title<step>.title
Description<step>.description
Field label<step>.field.<field>
Placeholder, help text<step>.field.<field>.placeholder, <step>.field.<field>.help
Buttonthe action's text_key in the flow file, or <step>.action.<action> if it has none
Back button<step>.action.back, or action.back if the step has none
Error messageerror.<code>, such as error.invalid_credentials
Notice that a sign-in went on as a sign-up, or the reversenotice.<reason>, such as notice.user_not_found

<field> is the field's name in the step's fields; a sign-in method field such as x-auth-methods#password uses the method, password. The flows zitadel setup creates give every button a text_key, so the email screen's Continue button, for example, is identifier.action.continue, not identifier.action.submit. Every built-in key and its English text is in the English dictionary. Keep any placeholder in braces, such as {0} or {name}, in a text you replace: the login fills it in, with a field's label or a provider's name.

Label a step you add

A step you add to your flow has no built-in text, so supply its keys in en: every visitor sees your English until you add their language. For a step named company-details with a company field and a submit action:

<ZitadelLogin
  locales={{
    en: {
      "company-details.title": "About your company",
      "company-details.field.company": "Company name",
      "company-details.action.submit": "Continue",
    },
  }}
/>

A key that no dictionary has shows on screen as the key itself, and the browser console warns missing text key: a button that reads company-details.action.submit names the entry to add. Fields are the exception: a missing label shows the field's name made readable, so dateOfBirth reads "Date of birth", and a missing placeholder or help text shows nothing. Keys that your own login design adds to its template work the same way.

Choose the language

The login shows the language set by lang, or the browser's language when lang is unset. It reads only the language, not the region: a browser set to de-CH gets de, so key locales by de, never de-CH.

For each key, a visitor gets the first of these that has a text for it:

  1. your entries for their language, such as de;
  2. the built-in texts for their language, if the login ships them;
  3. your en entries;
  4. the built-in English texts.

So your English is the fallback for every language: a step you labelled only in en reads in English for everyone. A built-in translation still beats it, so change a built-in text for German or Italian visitors with a de or it entry, or set lang="en" to show everyone English.

Steps that offer sign-in providers

A step that shows sign-in provider buttons asks for <step>.description.sso instead of <step>.description, because its text must also suit users who have no password. Only the password step has one built in, "Enter your password or continue with your sign-in provider"; every other step shows its plain description.

If you change a step's .description but not its .description.sso, your text shows whether or not the step offers providers.

Was this helpful?