Switching your application theme is getting more and more popular in recent years. APEX apps and their users are no exception. Most of our devices support this feature, APEX itself introduced dark and light mode for the Application Builder too. I am going to show you a quick way of integrating it into your application.
Possible use cases of theme switching
- Manual option for the user to switch between dark and light mode
- Automatic theme switch, based on your device (laptop, smartphone, etc.) settings
- Automatic theme switch, based on the time of the day (light during the day and dark during the night)
- A hybrid solution, where user can manually switch or select some of the automatic switch settings
This tutorial will cover a hybrid solution, including a manual change of the Theme Style and an automatic one, based on user’s device settings.
Possible approaches to the task
- The first approach will be to create
two seperate Theme Styles
in your app, withone global.css
file for the common styles. The style changes will be detected on page load, using Dynamic Actions and User’s preferences will be kept using Application Settings. This approach is described in the steps below. For the other approaches, there will be another blog post, going step-by-step. - The second approach would be with one Theme style only, but different CSS files for the Light and Dark theme. For example one common
global.css
(like in the previous approach) and two more files –light.css
anddark.css
. Depending on the themes selected, only one of the two files is loaded dynamically. To achieve this, useapex_theme.set_session_style_css
procedure – See documentation here. - … And a third approach – this is what APEX is using itself for changing the Builder theme style – CSS only approach, using something similar to this: https://css-tricks.com/dark-modes-with-css/. In this case you will have only one
global.css
file, but have the theme detection inside:
CSS Only Approach


- Create a file, named
global.css
inShared Components > Static Application Files
. The path to your file could be something like#APP_IMAGES#css/global.css
. Put the following styles inside.
/* Dark mode */
@media (prefers-color-scheme: dark) {
body {
background-color: black;
color: white;
}
}
/* Light mode */
@media (prefers-color-scheme: light) {
body {
background-color: white;
color: black;
}
}
- Go to
Edit Application Properties
, switch toUser Interface
tab, scroll down toCascading Style Sheets
section and add the following line –#APP_IMAGES#css/global#MIN#.css
. This will include your CSS file on every page of the app. What the#MIN#
part is doing is switching between the regular and minified version of the CSS file, depending if you are logged into the Builder or not. If you are logged in as a developer, you will be able to view the regular CSS and easily debug it. If you are just a user of the app, you will be served the.min.css
version, which is compressed, takes less space and loads faster, but is not suitable for development and debug purposes. All that is a new feature of Oracle APEX, which is very cool and I highly recommend using the#MIN#
syntax.
With this setup in place, your application will switch your background colour and text colour, as soon as the colour scheme of your device is changed – no waiting, an immediate change! Cool!
Switch two Theme Styles Approach


1. Create two different theme styles for your app
I have chosen the approach with one, common for all the styles, CSS file in Static Application Files
, called global.css
and two seperate theme styles, created using Theme Roller – Light Theme
and Dark Theme
.
Global.css would keep all the custom CSS we have in our app, except for the colour specific styles. They will be kept in the Custom CSS part of the Light and Dark theme in Theme Roller.
2. Create Application Settings
The Application settings will help keeping the User preferences for Theme Style Mode and Theme Style Name. To create new application settings, go to Shared Components > Application Settings
. Then create two new settings, named THEME_STYLE_MODE
and THEME_STYLE_NAME
.
The Application settings are read and written using the following methods:
apex_app_setting.get_value('THEME_STYLE_MODE');
apex_app_setting.set_value('THEME_STYLE_MODE',:P0_THEME_STYLE_MODE);
3. Create Application Items
From Shared Components > Application Items
, create two new items – G_THEME_STYLE_MODE
and G_THEME_STYLE_NAME
.
4. Create Application Computations
The Application items we created on step 3, will be populated with default values, when the user is logged into the application. Those values will be taken from user’s preferences which we created in step 2.
- Computation Item –
G_THEME_STYLE_MODE
- Computation Point –
After Authentication
- Computation Type –
Expression
- Language –
PL/SQL
- Computation –
apex_app_setting.get_value('THEME_STYLE_MODE');
- Computation Item –
G_THEME_STYLE_NAME
- Computation Point –
After Authentication
- Computation Type –
Expression
- Language –
PL/SQL
- Computation –
apex_app_setting.get_value('THEME_STYLE_NAME');
5. Create Application Processes
We will need one Application Process to check if a Theme Style has been changed by a Dynamic Action on page 0. If so, the process will change a flag and indicate that a reload is needed.
checkThemeRefresh
A Radion Group type again, with two static values – Dark Theme and Light Theme. And a default value –G_THEME_STYLE_NAME
.
Server-side condition will be the following:
Process Point : Ajax Callback
Name : checkThemeRefresh
Language: PL/SQL
Code:
declare
l_theme varchar2(100) := apex_application.g_x01;
l_changed varchar2(3);
begin
APEX_DEBUG.ENABLE (p_level => 2);
case
when l_theme = 'Clay Lacy Dark' and :P0_CURRENT_THEME_CHANGED = 'Yes' then
:P0_CURRENT_THEME_STYLE := 'Light Theme';
:P0_THEME_STYLE_NAME := 'Light Theme';
when l_theme = 'Light Theme' and :P0_CURRENT_THEME_CHANGED = 'Yes' then
:P0_CURRENT_THEME_STYLE := 'Dark Theme';
:P0_THEME_STYLE_NAME := 'Dark Theme';
else :P0_CURRENT_THEME_STYLE := l_theme;
end case;
l_changed := :P0_CURRENT_THEME_CHANGED;
apex_debug.info(':P0_CURRENT_THEME_CHANGED -> '||l_changed);
apex_json.open_object;
apex_json.write('success', true);
apex_json.write('p_refresh_theme', l_changed);
apex_json.close_object;
APEX_DEBUG.DISABLE;
end;
6. On Page 0, create some global regions and Dynamic Actions
-
P0_THEME_STYLE_MODE
It can be a Radion Group type, with two static values – Dark Theme and Light Theme. And a default value –G_THEME_STYLE_MODE
. -
P0_THEME_STYLE_NAME
A Radion Group type again, with two static values – Dark Theme and Light Theme. And a default value –G_THEME_STYLE_NAME
.
Server-side condition will be the following:
Type : Item = Value
Item : P0_THEME_STYLE_NAME
Value: manual
This way, the item will be hidden if we are not selecting the Theme Style manually.
P0_CURRENT_THEME_CHANGED
andP0_CURRENT_THEME_STYLE
Those will help us know if the theme has changed. They are later used in some of the Dynamic Actions. Their type is Display Only, because otherwise (as a hidden item for example) they will not be available with using JavaScript (and we nwill need that).
7. On Page 0, create some Dynamic Actions
onLoad - Auto switch Theme Style (device)
Event : Page Load
Client-side Condition
Type : Javascript expression
Javascript expression :
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
Server-side Condition
Type : Item = Value
Item : G_THEME_STYLE_MODE
Value: device
True
- Action :
Execute Server-side Code
Language :PL/SQL
PL/SQL Code:
declare
l_current_Theme_style_name apex_application_theme_styles.name%type;
begin
select s.name theme_style_name
into l_current_Theme_style_name
from apex_application_theme_styles s
where s.Theme_style_id = apex_theme.get_user_style( :APP_ID, :APP_USER, 42 );
for c1 in (select t.theme_number,
s.name theme_style_name,
s.theme_style_id,
s.is_current is_current
from apex_application_theme_styles s, apex_application_themes t
where s.application_id = t.application_id
and s.theme_number = t.theme_number
and s.application_id = :app_id
and lower(s.name) = 'dark theme'
order by 1 )
loop
apex_theme.set_user_style (
p_application_id => :APP_ID,
p_user => :APP_USER,
p_theme_number => c1.theme_number,
p_id => c1.theme_style_id );
if lower(l_current_Theme_style_name) 'dark theme' then
:P0_CURRENT_THEME_CHANGED := 'Yes';
:P0_CURRENT_THEME_STYLE := 'Dark Theme';
else
:P0_CURRENT_THEME_CHANGED := 'No';
end if;
:P0_THEME_STYLE_NAME := 'Dark Theme';
end loop;
end;
- Action :
Execute JavaScript Code
Language :PL/SQL
PL/SQL Code:
apex.server.process("checkThemeRefresh", // Process or AJAX Callback name
{x01: "Clay Lacy Dark"}, // Parameter "x01"
{
success: function (pData) { // Success Javascript
if (pData.p_refresh_theme === 'Yes') {
apex.submit();
console.log("Theme style changed from Light Mode to Dark Mode. Page was refreshed.");
console.log("Your application is now in Dark Mode.");
} else {
console.log("pData.p_refresh_theme -> " + pData.p_refresh_theme);
}
}
}
);
False
- Action :
Execute Server-side Code
Language :PL/SQL
PL/SQL Code:
declare
l_current_Theme_style_name apex_application_theme_styles.name%type;
begin
select s.name theme_style_name
into l_current_Theme_style_name
from apex_application_theme_styles s
where s.Theme_style_id = apex_theme.get_user_style( :APP_ID, :APP_USER, 42 );
for c1 in (select t.theme_number,
s.name theme_style_name,
s.theme_style_id,
s.is_current is_current
from apex_application_theme_styles s, apex_application_themes t
where s.application_id = t.application_id
and s.theme_number = t.theme_number
and s.application_id = :app_id
and lower(s.name) = 'light theme'
order by 1 )
loop
apex_theme.set_user_style (
p_application_id => :APP_ID,
p_user => :APP_USER,
p_theme_number => c1.theme_number,
p_id => c1.theme_style_id );
if lower(l_current_Theme_style_name) 'light theme' then
:P0_CURRENT_THEME_CHANGED := 'Yes';
:P0_CURRENT_THEME_STYLE := 'Light Theme';
else
:P0_CURRENT_THEME_CHANGED := 'No';
end if;
:P0_THEME_STYLE_NAME := 'Light Theme';
end loop;
APEX_DEBUG.ENABLE;
apex_debug.info('APP_ID -> '||:APP_ID);
apex_debug.info('APP_USER -> '||:APP_USER);
APEX_DEBUG.DISABLE;
end;
- Action :
Execute JavaScript Code
Language :PL/SQL
PL/SQL Code:
apex.server.process("checkThemeRefresh", // Process or AJAX Callback name
{x01: "Light Theme"}, // Parameter "x01"
{
success: function (pData) { // Success Javascript
if (pData.p_refresh_theme === 'Yes') {
apex.submit();
console.log("pData.p_refresh_theme -> " + pData.p_refresh_theme);
console.log("Theme style changed from Dark Mode to Light Mode. Page was refreshed.");
console.log("Your application is now in Light Mode.");
} else {
console.log("pData.p_refresh_theme -> " + pData.p_refresh_theme);
}
}
}
);
onChange - Switch theme style name
Event : Change
Selection Type : Item(s)
Item(s) : P0_THEME_STYLE_NAME
True
- Action :
Execute Server-side Code
Language :PL/SQL
PL/SQL Code:
begin
apex_app_setting.set_value('THEME_STYLE_NAME',:P0_THEME_STYLE_NAME);
apex_util.set_session_state('G_THEME_STYLE_NAME', :P0_THEME_STYLE_NAME);
for c1 in (select t.theme_number,
s.name theme_style_name,
s.theme_style_id,
s.is_current is_current
from apex_application_theme_styles s, apex_application_themes t
where s.application_id = t.application_id
and s.theme_number = t.theme_number
and s.application_id = :app_id
and lower(s.name) = lower(:P0_THEME_STYLE_NAME)
order by 1 )
loop
apex_theme.set_user_style (
p_application_id => :APP_ID,
p_user => :APP_USER,
p_theme_number => c1.theme_number,
p_id => c1.theme_style_id );
APEX_DEBUG.ENABLE (p_level => 2);
apex_debug.info(':P0_CURRENT_THEME_CHANGED -> '||:P0_CURRENT_THEME_CHANGED);
apex_debug.info(':P0_THEME_STYLE_NAME -> '||:P0_THEME_STYLE_NAME);
apex_debug.info('theme_style_name -> '||c1.theme_style_name);
APEX_DEBUG.DISABLE;
end loop;
end;
Items to Submit : P0_THEME_STYLE_NAME
Items to Return : P0_CURRENT_THEME_CHANGED
,P0_CURRENT_THEME_STYLE
,G_THEME_STYLE_NAME
- Action :
Submit Page
onChange - Switch theme style mode
Event : Change
Selection Type : Item(s)
Item(s) : P0_THEME_STYLE_MODE
True
- Action :
Execute Server-side Code
Language :PL/SQL
PL/SQL Code:
apex_app_setting.set_value('THEME_STYLE_MODE',:P0_THEME_STYLE_MODE);
apex_util.set_session_state('G_THEME_STYLE_MODE', :P0_THEME_STYLE_MODE);
Items to Submit : P0_THEME_STYLE_MODE
Items to Return : G_THEME_STYLE_MODE
- Action :
Submit Page