Every Ramadan I look at the apps and portals we build and think – why does everything feel so… corporate? Dark sidebar, data table, pagination, done. For a month that means so much to so many people, the least we can do is build something that actually feels like it.
This year I decided to do something about it. I built a full interactive Ramadan Calendar directly inside Oracle APEX. No external plugins, no iframes, no third-party libraries. Just clean HTML, CSS Grid, JavaScript date logic, and a little bit of APEX dynamic actions.
And the best part? It handles multiple countries. My team is split across Pakistan and Germany – they have different Ramadan start dates. One select list, and the whole calendar recalculates. Simple, but it matters a lot when your users are global.
Let me show you how I built it.
What We’re Building
The calendar has two parts:
- A premium dark sidebar with the title, an Arabic Quranic verse, and the reference – gives the whole thing a meaningful, elegant feel
- An interactive calendar grid that generates all 30 days dynamically, highlights Lailat-ul-Qadr (the 27th night), and auto-calculates Eid al-Fitr
The location selector at the top sits in a collapsible region styled in emerald and gold. When the user changes the country, the calendar refreshes instantly. No page reload.
Built on Oracle APEX 23.2. Let’s get into it.
Step 1: The Setup
You need two things before writing a single line of CSS or JavaScript.
Page Item: P1_LOCATION
Create a Select List page item called P1_LOCATION. Set the static values like this:
- Pakistan → 2025-02-28
- Germany → 2025-03-01
Yes, the value is the actual start date string. JavaScript will parse it directly. No extra server calls needed.
Collapsible Region
Create a region with:
- Template: Collapsible
- Static ID: ramadan_selector_reg
The Static ID is critical – our CSS targets it directly to override the default APEX theme styling.
Step 2: The Styling
This is where we break out of the standard APEX Universal Theme look. Paste this in the Page’s Inline CSS section.
The color palette is intentional – deep emerald (#064e3b) and muted gold (#bda36b). It reads “premium” without being flashy.
/* Premium Emerald & Gold Collapsible Bar */
#ramadan_selector_reg {
background-color: #064e3b !important;
border: 1.5px solid #bda36b !important;
border-radius: 8px;
}
#ramadan_selector_reg .t-Region-header {
background-color: #064e3b !important;
}
#ramadan_selector_reg .t-Region-headerTitle,
#ramadan_selector_reg .t-Icon {
color: #bda36b !important;
font-family: 'Montserrat', sans-serif;
}
/* The Overlapping Dashboard UI */
.rp-container {
display: flex;
background: #fff;
min-height: 600px;
border-radius: 4px;
overflow: hidden;
}
.rp-sidebar {
width: 40%;
background: #15242b;
color: #fff;
padding: 60px 40px;
position: relative;
}
.rp-main-title {
font-family: 'Cinzel', serif;
font-size: 3.5rem;
color: #bda36b;
letter-spacing: 10px;
}
.rp-ayat-section {
border-left: 2px solid #bda36b;
padding-left: 20px;
margin-top: 30px;
}
.rp-arabic {
font-family: 'Amiri', serif;
font-size: 1.8rem;
color: #bda36b;
}
.rp-calendar-main {
width: 60%;
padding: 40px;
background: #fdfdfd;
}
.rp-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 30px 15px;
width: 100%;
}
.qadr-mark {
color: #bda36b !important;
font-weight: 700 !important;
}
A few things worth calling out here:
- The !important flags on the collapsible region are necessary – APEX’s Universal Theme is stubborn with its own styles. You have to override it explicitly.
- display: flex on .rp-container is what gives us that clean sidebar-plus-content layout. The sidebar gets 40%, the calendar gets 60%.
- grid-template-columns: repeat(6, 1fr) means 6 equal columns, so 30 days fills out nicely in 5 rows. CSS Grid is honestly perfect for this.
- Cinzel and Amiri fonts – Cinzel gives the title that engraved, historical look. Amiri is specifically designed for Arabic calligraphy. Both are available from Google Fonts – just add the import in your page’s CSS or load them in the app’s User Interface attributes.
Step 3: The HTML Structure
Create a Static Content region and drop this into its Source. This is the shell – the JavaScript will fill in the actual calendar days.
<div class="rp-container">
<div class="rp-sidebar">
<div class="rp-content">
<h1 class="rp-main-title">RAMADAN</h1>
<div class="rp-ayat-section">
<p class="rp-arabic">
شَهْرُ رَمَضَانَ الَّذِي أُنزِلَ فِيهِ الْقُرْآنُ
</p>
<p class="rp-english">
"The month of Ramadan is that in which was revealed the Qur'an..."
</p>
<span class="rp-ref">Surah Al-Baqarah 2:185</span>
</div>
</div>
</div>
<div class="rp-calendar-main">
<div id="calendar-grid" class="rp-grid"></div>
</div>
</div>
Notice the calendar-grid div is completely empty at this point. Intentionally. JavaScript builds it dynamically so it reacts to whichever country the user picks. The sidebar content is static – it’s the same verse and reference regardless of location.
Step 4: The JavaScript Logic
This is where it all comes together. Create a Dynamic Action:
- Event: Change
- Selection Type: Item
- Item: P1_LOCATION
- Fire on Initialization: YES – this is important, otherwise the calendar won’t render on page load
Then add an Execute JavaScript Code action with this:
const startDateStr = apex.item("P1_LOCATION").getValue();
const grid = document.getElementById("calendar-grid");
grid.innerHTML = "";
if (startDateStr) {
let startDate = new Date(startDateStr);
for (let i = 1; i <= 30; i++) {
let currentDate = new Date(startDate);
currentDate.setDate(startDate.getDate() + (i - 1));
let fmtDate = currentDate.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric'
});
let dayDiv = document.createElement("div");
dayDiv.className = "rp-day-cell";
let isQadr = (i === 27);
dayDiv.innerHTML = `
<span class="rp-day-label ${isQadr ? 'qadr-mark' : ''}">
${i}
</span>
<span class="rp-date-label">
${isQadr ? 'Lailat-ul-Qadr' : fmtDate}
</span>
`;
grid.appendChild(dayDiv);
}
// Eid al-Fitr - the day after the 30th
let eidDate = new Date(startDate);
eidDate.setDate(startDate.getDate() + 30);
let eidFormatted = eidDate.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric'
});
let eidDiv = document.createElement("div");
eidDiv.className = "rp-day-cell";
eidDiv.innerHTML = `
<span class="rp-day-label qadr-mark">Eid</span>
<span class="rp-date-label">${eidFormatted}</span>
`;
grid.appendChild(eidDiv);
}
Let me break down what’s happening here:
- apex.item().getValue() reads the date string directly from the select list. No AJAX, no page submission.
- new Date(startDateStr) parses that string into a JavaScript Date object. From there we can do all kinds of date math.
- The loop runs 30 times, creating a div for each day and calculating the actual calendar date using setDate(). Because we create a new Date object each iteration, we don’t mutate the original startDate.
- Day 27 gets special treatment – the isQadr flag replaces the date label with ‘Lailat-ul-Qadr’ and applies the gold styling via qadr-mark class.
- Eid al-Fitr is calculated as the day after the 30th of Ramadan. Simple date math, appended as the 31st cell in the grid.
Why the Location Toggle Matters
This might seem like a small feature – just a select list with two options. But think about it from your users’ perspective.
If you’re building internal tools for a company with offices in multiple countries, Ramadan doesn’t start on the same day everywhere. The moon sighting differs by region. A Pakistani employee and a German colleague are both fasting, but potentially starting a day apart.
When you build with that in mind – when you let each person switch to their own start date – you’re saying: we see you, we built this for you specifically. That’s a small thing technically but a big thing culturally. And it takes maybe 10 extra minutes to implement.
Breaking Out of the Standard APEX Look
One of the most common things I hear from developers is “APEX apps all look the same.” And honestly? That’s a choice, not a limitation.
Universal Theme is a fantastic foundation but it’s just that – a foundation. The moment you start treating APEX regions as containers for your own HTML and CSS, the whole thing opens up. What we built here doesn’t look like a typical APEX report because it isn’t one. It’s a custom HTML layout that happens to live inside APEX.
The key techniques that made this possible:
- Static Content regions as raw HTML containers – drop any HTML you want, style it yourself
- Inline CSS for page-specific overrides – don’t be afraid of !important when fighting theme defaults
- Dynamic Actions with JavaScript – you have full access to the DOM. Use it
- Google Fonts in APEX – load Cinzel, Amiri, Montserrat via the app’s User Interface > CSS > File URLs. Typography transforms how a UI feels completely
Final Thoughts
This project took maybe 1 hour total. The result is something that actually looks and feels special – not like a database form wrapped in a theme.
Ramadan Mubarak to everyone observing. I hope this inspires you to build something meaningful this month – not just functional, but thoughtful.
If you want to extend this further, some ideas:
- Add Sehri and Iftar times per location (pull from a reference table or API)
- Let users mark personal goals for each day of Ramadan
- Add more countries – Indonesia, Turkey, UAE – each with their own start dates
- Style the Eid cell differently – bigger, gold border, celebration icon
As always, feel free to reach out if you get stuck or want to share what you built. I am always happy to talk about APEX.
Hassan Raza
Oracle ACE Apprentice, Pakistan