Mastering Light & Dark Themes in Forge Apps
Andrei Pisklenov
Head of Development | Passionate Full-Stack Enthusiast (Typescript & Java) | Certified Atlassian Expert
Overview
I have an exciting idea for an application tailored for the Atlassian Marketplace. Picture this: your team is in the middle of sprint planning, tasked with estimating a new feature in story points. But there's a problem - team members can't reach a consensus. Some are convinced of one estimate, while others argue for a different number, leading to a stalemate. What can be done to resolve this deadlock?
Enter a new kind of solution: an application that invites the entire team to sing a motivating song together. After that, the energy shifts, and the team is not only more motivated but also better aligned, enabling quicker and more efficient decision-making.
The app must look great in both light and dark themes. After all, many developers swear by the dark mode, and without this option, they might not be as enthusiastic about participating. Ensuring a visually appealing interface in both themes is critical for the app's success.
This new application will be developed for Jira Cloud, leveraging the power of the Forge framework to create a seamless and engaging experience.
First Proof of Concept
We're not going to dive into the step-by-step process of building an app from scratch here - we've got plenty of guides for that (One App to Rule Them All: Conquer Jira Cloud with All Atlassian Forge Modules in a Single App! , Essential Guide to Atlassian Forge Modules for Jira ). For now, let's say we've used the Forge Issue Panel module to display our app’s content, paired with React for a Custom UI. Fast-forward through the setup, and voilà, our first version of the app is up and running! (Picture it: light theme on the left, dark theme on the right).
It’s clearly amazing... but let’s be honest, it’s not quite looking like a Jira-native masterpiece just yet. Here’s what we need to fix:
Resetting basic styles
A quick and easy win? Just one simple import from the css-reset (check it out here: https://atlassian.design/components/css-reset/examples) and boom - your padding, margins, and fonts are instantly aligned with Jira’s look.
// index.tsx
import '@atlaskit/css-reset';
And voilà! The result is looking a bit better. The font now matches Jira's, which is great... but sadly, the colors and background? Still off. Baby steps, right?
Enabling Theme and Design Tokens
So, after bravely conquering this massive guide (https://developer.atlassian.com/platform/forge/design-tokens-and-theming/), we’re ready to make two key updates to our app:
1. Wrap all our code in the index.tsx file with the magic snippet below.
// index.tsx
import { view } from '@forge/bridge';
import ReactDOM from 'react-dom/client';
import { App } from './app/App';
import '@atlaskit/css-reset';
void view.theme.enable().then(() => {
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<App />,
);
});
2. Replace all those hard-coded color names with sleek “tokens” like this example.
领英推荐
import { token } from '@atlaskit/tokens';
export const App = () => {
return (
<div>
<button>Next song</button>
<div
style={{
color: token('color.text'),
whiteSpace: 'pre-line',
}}
>
... the rest part of the App ...
And guess what? The result looks way better - whether you’re rocking Light or Dark mode, the fonts, colors, and spacing are all on point now.
UI Components
Time for a few more tweaks - let’s upgrade our buttons and any other controls with some proper UI components. Trying to manually match Jira’s CSS styles? That’s a wild goose chase. Instead, we can use the same UI framework that Jira uses for its own elements: (https://atlaskit.atlassian.com/). It’s got everything you need for the UI - buttons, labels, inputs, tables, you name it.
import Button from '@atlaskit/button/new';
import { Box } from '@atlaskit/primitives';
import { token } from '@atlaskit/tokens';
export const App = () => {
return (
<Box>
<Button>Next song</Button>
<Box
style={{
color: token('color.text'),
whiteSpace: 'pre-line',
}}
>
... the rest part of the App ...
The result? Our buttons (and everything else) will look just like they do in Jira. Success, right?
Wait, does this mean we’ve finally achieved a fully native-looking app in both light and dark themes? Can we start selling it on the Marketplace?! Well, almost… except for one small thing. There’s still that pesky issue with “raised” views, like when an Issue View pops up in a modal window (you know, when you click on an issue from the List view).
Background for Raised Views
To tackle that last little issue, we’ll create a styles.css file with the following magic:
/* styles.css */
html,
body,
#root {
background-color: transparent; /* fix for raised views */
}
Then, just import it into your index.tsx like this:
// index.tsx
import './styles.css';
And behold the beauty! Raised views now blend in perfectly. It’s like the finishing touch on a masterpiece.
Conclusion
Achieving flawless light and dark theme support for your Custom UI is easy - ust follow these four simple steps:
I was totally going to share the source code, but then I realized it’s so amazing that I have no choice but to sell it on the Atlassian Marketplace - as soon as they introduce the ‘Amazing Apps for Motivation’ category. Stay tuned!
Content Marketing Manager at Seibert Group GmbH (appanvil), #AtlassianCreator, author, Black Forest-Lover
2 周This is a brilliant idea! ?? Integrating a fun, interactive approach like singing a song could be a fantastic way to shift team energy and resolve disagreements. It's also great to see the focus on seamless design across light and dark themes—definitely a must-have for developers.
Product Owner of Report Builder (Actonic GmbH)
2 周Quote: "I was totally going to share the source code, but then I realized it’s so amazing that I have no choice but to sell it on the Atlassian Marketplace - as soon as they introduce the ‘Amazing Apps for Motivation’ category. Stay tuned!" ------- May I wonder if you consider releasing it under any other category Andrei Pisklenov? ??