Styles

Styles help you create and scale user-facing screens while adhering to your brand’s guidelines. You can add your brand’s logo, colors, and other design elements in a central location in the Descope UI. Any screens you create with the Screen Builder will take on the brand elements from Styles.

If your brand goes through updates, Styles also makes it easy to propagate those updates to all your user-facing screens.

In Descope, we offer the option to customize your user experience through the styles page. Those options consist of varying properties as the logo of your company, the fonts that the components will inherit, and much more. Those options are selections we predefine, and some are limited. Some Descopers want to take a step further and customize their user experience to a new extent, such as custom fonts and self-defined CSS stylings. This article will show you the basics of how to use Descope's gui/code mode on the styling page.

GUI Mode

Descope has Styles divided into two tabs. Theme tab provides global styling option that affect the overall screens and individual components. With the Components tab, you can configure each component in detail.

Styling Themes

Under the Theme tab, we have three sections that we can customize according to our brand. Each of these sections are available for both Light and Dark themes.

Logo

You can upload your company's logo under this field with a simple drag and drop. Same goes for the dark theme option as well.

GUI screen Logo.

Colors

In this section, you can select your brand colors to match brand consistency. You have options of designing Primary, Secondary, Greys, Success and Error.

When you select a primary color for example, Descope will create the rest of the palette for you.

GUI screen Colors.

Typography

In this section, you can choose font families for all the text related components. You have a list of fonts available from the dropdown. Additionally, all the way at the top of the dropdown, Descope provides an option to add a custom font.

Each of the different sections like Headings, Subtitles, Body can be customized with different font, size and weight.

GUI screen Fonts.

Custom Font
Each font family allows one custom font setting. To configure a custom font, click the + Add Font from the font dropdown, then provide a family name and a url to the hosted font file. Descope also allows editing the custom font after its been intially set.

GUI custom Fonts.

Styling Components

Under the Components tab, you can set the buttons according to your branding in more detail. Every button/component has an editable action provided on the right side.

GUI screen buttons components.

You can configure options for Font Family, Border Radius, Border Width, Text/Background color etc for your primary or secondary buttons. It also gives you a choice to add custom configurations.

For Oauth buttons, you can customize each button by provider name. Example: Here for provider Apple, you can customize the button accordingly or just leave it to default.

GUI screen oauth button components.

Once all the changes are made, you can click Apply and view your changes in preview mode by clicking the Preview button.

Code Mode

Enable code mode editor with a toggle button. Clicking the button will switch the styles page to code mode:

Code Mode button Descope.

The styles page should look like this:

Code Mode screen Descope.

Note: Styles between light and dark theme will not persist, meaning each theme holds different values.

Best Practices

Most of the fields inside code mode are self explained by name, and can be tested right away in the flow builder. Some best practices and odd features are documented here:

Components

  • Badge: Is the styling of the component of the options you get inside a multi-select field:

Code Mode badge component explination.
  • Logo: Contains the values of the URL's for the company logo that will be used, including the fallback URL:
    "logo": {
      "--descope-logo-fallback-url": "url(https://imgs.descope.com/components/no-logo-placeholder.svg)",
      "--descope-logo-url": "https://static.descope.com/pages/P2XCa7FBmpm6zN1agE26uEImPpXo/v2-alpha/light/logo.png"
    }
  • TOTP Image: Holds the placeholder image for TOTP button
    "totpImage": {
      "--descope-totp-image-fallback-url": "url(https://imgs.descope.com/components/totp-placeholder.svg)"
    }
  • Required Attribute: If a component supports using the required boolean, the '_required' attribute will appear in code mode, stating which component will it use to indicate it:
"_required": {
        "--descope-upload-file-required-indicator": "var(--descope-input-wrapper-required-indicator)"
      }
  • notificationCard: can alter the style of the notification toast you and other Descopers will get, also how different types of modes will be displayed, such as errors and success messages for actions performed in Descope:
      "mode": {
        "error": {
          "--descope-notification-card-background-color": "var(--descope-colors-error-main)",
          "--descope-notification-card-border-color": "var(--descope-colors-error-light)",
          "--descope-notification-card-text-color": "var(--descope-colors-error-contrast)"
        },
        "primary": {
          "--descope-notification-card-background-color": "var(--descope-colors-primary-main)",
          "--descope-notification-card-border-color": "var(--descope-colors-primary-light)",
          "--descope-notification-card-text-color": "var(--descope-colors-primary-contrast)"
        },
        "success": {
          "--descope-notification-card-background-color": "var(--descope-colors-success-main)",
          "--descope-notification-card-border-color": "var(--descope-colors-success-light)",
          "--descope-notification-card-text-color": "var(--descope-colors-success-contrast)"
        }
      },
  • Special Attributes: Some components hold styling states for states of the components, using the attributes listed below, altering them, will change how the component will look at different states:
      {
      "_checked": {
        ...
      },
      "_disabled": {
        ...
      },
      "_invalid": {
        ...
      },
      "_readonly":{
        ...
      },
      "_focused":{
        ...
      },
      "_vertical":{
        ...
      },
      "_fullWidth":{

      },
      "_loading":{
        ...
      },
      "_square":{
        ...
      },
      "_bordered":{
        ...
      },
      "_hidden":{
        ...
      },
      "_hideCursor":{
        ...
      }
      // special for text component:
      "_italic":{
        ...
      },
      "_lowercase":{
        ...
      },
      "uppercase":{
        ...
      }
      }

Globals

  • Direction: Possible inputs: 'ltr' / 'rtl' - a global variable that will determine if your components will be Right To Left or Left To Right.
  • Fonts: You can add a url to both 'font1' and font2' to use a custom font, make sure you create a label that you will remember.
      "font1": {
        "family": [],
        "label": "Custom",
        "url": "https://MyCustomFont.Url/font"
      }
  • Typography: You can determine what component types will take which font.
      "body1": {
        "font": "var(--descope-fonts-font1-family)",
        "size": "14px",
        "weight": "500"
      }

Exporting and Importing Theme from Console

Once you have defined your styles, you can export or import the styles using the up and down arrows at the top right of the styles page. This feature allows you to backup your current styles, or migrate them between your projects.


Descope screen styling example.

Exporting and Importing Styles from the Management SDK

The Descope SDK allows you to import and export themes.

Install SDK

NodeJSPythonGoJavaRuby
npm i --save @descope/node-sdk
pip3 install descope
go get github.com/descope/go-sdk
// Include the following in your `pom.xml` (for Maven)
<dependency>
    <artifactId>java-sdk</artifactId>
    <groupId>com.descope</groupId>
    <version>sdk-version</version> // Check https://github.com/descope/descope-java/releases for the latest versions
</dependency>
gem install descope

Import and initialize Management SDK

NodeJSPythonGoJavaRuby
import DescopeClient from '@descope/node-sdk';

const managementKey = "xxxx"

try{
    //  baseUrl="<URL>" // When initializing the Descope clientyou can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize CNAME within your Descope project.
    const descopeClient = DescopeClient({ projectId: '__ProjectID__', managementKey: managementKey });
} catch (error) {
    // handle the error
    console.log("failed to initialize: " + error)
}

// Note that you can handle async operation failures and capture specific errors to customize errors.
//     An example can be found here: https://github.com/descope/node-sdk?tab=readme-ov-file#error-handling
from descope import (
    REFRESH_SESSION_TOKEN_NAME,
    SESSION_TOKEN_NAME,
    AuthException,
    DeliveryMethod,
    DescopeClient,
    AssociatedTenant,
    RoleMapping,
    AttributeMapping
)

management_key = "xxxx"

try:
    # You can configure the baseURL by setting the env variable Ex: export DESCOPE_BASE_URI="https://auth.company.com  - this is useful when you utilize CNAME within your Descope project."
    descope_client = DescopeClient(project_id='__ProjectID__', management_key=management_key)
except Exception as error:
    # handle the error
    print ("failed to initialize. Error:")
    print (error)
import "github.com/descope/go-sdk/descope"
import "github.com/descope/go-sdk/descope/client"
import "fmt"

// Utilizing the context package allows for the transmission of context capabilities like cancellation
//      signals during the function call. In cases where context is absent, the context.Background()
//      function serves as a viable alternative.
//      Utilizing context within the Descope GO SDK is supported within versions 1.6.0 and higher.
import (
	"context"
)

managementKey = "xxxx"

// DescopeBaseURL // within the client.Config, you can also configure the baseUrl ex: https://auth.company.com  - this is useful when you utilize CNAME within your Descope project.
descopeClient, err := client.NewWithConfig(&client.Config{ProjectID:"__ProjectID__", managementKey:managementKey})
if err != nil {
    // handle the error
    log.Println("failed to initialize: " + err.Error())
}
import com.descope.client;

// Initialized after setting the DESCOPE_PROJECT_ID env var (and optionally DESCOPE_MANAGEMENT_KEY)
var descopeClient = new DescopeClient();

// ** Or directly **
var descopeClient = new DescopeClient(Config.builder()
        .projectId("__ProjectID__")
        .managementKey("management-key")
        .build());
require 'descope'


descope_client = Descope::Client.new(
  {
    project_id: '__ProjectID__',
    management_key: 'management_key'
  }
)

Export Theme

Use the code below to export a theme.

NodeJSPythonGo
import * as fs from 'fs';

// Args
//   None

const resp = await descopeClient.management.theme.export()
if (!resp.ok) {
  console.log(resp)
  console.log("Unable to export theme.")
  console.log("Status Code: " + resp.code)
  console.log("Error Code: " + resp.error.errorCode)
  console.log("Error Description: " + resp.error.errorDescription)
  console.log("Error Message: " + resp.error.errorMessage)
}
else {
  console.log("Successfully exported theme.")
  console.log(resp.data)
  let data = JSON.stringify(resp.data, null, 2);
  fs.writeFile('theme.json', data, (err) => {
      if (err) throw err;
      console.log('Theme written to file');
  });
}
import json

# Args
#   None
try:
  resp = descope_client.mgmt.flow.export_theme()
  print ("Successfully exported theme")
  print (resp)

  json_object = json.dumps(resp, indent=4)
  with open("theme.json", "w") as outfile:
    outfile.write(json_object)
except AuthException as error:
  print ("Failed to export theme")
  print ("Status Code: " + str(error.status_code))
  print ("Error: " + str(error.error_message))
import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strings"
)

// Args
//   None
res, err := descopeClient.Management.Flow().ExportTheme()
if err != nil {
  fmt.Print("Failed to export theme", err)
} else {
  data, err :=json.Marshal(res)
  if err == nil {
    fileName := fmt.Sprintf("theme.json")
    if err == nil {
      err = os.WriteFile(fileName, data, 0644)
      fmt.Println("Successfully exported flow")
    }
  }
}

Import Theme

Use the code below to import a theme.

NodeJSPythonGo
import * as fs from 'fs';

// Args
// theme (Theme): the theme to import. dict in the format
//    {"id": "", "cssTemplate": {} }

let data = fs.readFileSync('theme.json');
let jsonData = JSON.parse(data);
const theme = jsonData["theme"]

const resp = await descopeClient.management.theme.import(theme)
if (!resp.ok) {
  console.log(resp)
  console.log("Unable to import theme.")
  console.log("Status Code: " + resp.code)
  console.log("Error Code: " + resp.error.errorCode)
  console.log("Error Description: " + resp.error.errorDescription)
  console.log("Error Message: " + resp.error.errorMessage)
}
else {
  console.log("Successfully imported theme.")
  console.log(resp.data)
}
import json

# Args
# theme (Theme): the theme to import. dict in the format
#    {"id": "", "cssTemplate": {} }

with open("theme.json", "r") as infile:
  themeJson = json.load(infile)
theme = themeJson["theme"]
try:
  resp = descope_client.mgmt.flow.import_theme(theme=theme)
  print ("Successfully imported theme")
  print (resp)
except AuthException as error:
  print ("Failed to import theme")
  print ("Status Code: " + str(error.status_code))
  print ("Error: " + str(error.error_message))
import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strings"
)

// Args
// theme (Theme): the theme to import. dict in the format
//    {"id": "", "cssTemplate": {} }
raw, err := os.ReadFile("theme.json")
if err != nil {
  return err
}
theme := &descope.Theme{}
err = json.Unmarshal(raw, theme)
if err != nil {
  return err
  }
res, err := descopeClient.Management.Flow().ImportTheme(theme)
if err != nil {
fmt.Print("Failed to import flow", err)
} else {
  fmt.Print("Successfully imported flow", res)
}