Power Apps Calendar: A DIY Approach to Date Grids
Construct a full-month calendar view using galleries and formula logic—ready for scheduling, event tracking, or attendance apps.
Building a custom calendar grid is one of those projects that teaches you how Power Apps really works under the hood. Instead of relying on the out-of-the-box calendar screen, you gain control over every pixel of the date grid, navigation logic, and event handling. In this guide I’ll show you how to create a monthly calendar from scratch — no external components, no complex configuration — just galleries and Power Fx.
Once you’ve mastered the grid, you can extend it to show approvals, deadlines, or even team availability. Let’s start with a concrete scenario.
Example Scenario
Imagine you are building an Employee Leave Calendar for a small team. Each month managers need a quick view of who is on leave and which days are public holidays. The calendar must:
- Display all days of the current month in a grid, with Sunday as the first column.
- Show the name of the month and the year.
- Allow navigation to previous/next months.
- Highlight today’s date.
- Prepare for future integration with a SharePoint list named
LeaveRecords(columns:Employee,Date,Status).
In this first part we focus only on the month grid itself. Event data handling will follow in a separate article.
Setting Up the Month Grid
Start with a blank canvas in Power Apps (tablet or phone). I’ll assume you know how to insert controls and write Power Fx.
1. Store the “Viewing Month”
Place a button named btn_Today somewhere on the screen (later you can move it). Give it the text "Today". This button will reset the calendar to the current month.
Set its OnSelect to:
Set(varViewMonth, Date(Year(Today()), Month(Today()), 1))
We also need this variable to be set when the screen loads. Go to the Screen’s OnVisible property and enter the same code:
Set(varViewMonth, Date(Year(Today()), Month(Today()), 1))
varViewMonth always holds the first day of whatever month the user is looking at.
2. Generate the 42‑day Sequence
A standard month grid covers at most 6 weeks × 7 days = 42 cells. We’ll generate exactly 42 dates starting from the first Sunday before or equal to the first day of the month.
Insert a Vertical Gallery (let’s name it gal_CalendarGrid) and set its Items property:
ForAll( Sequence(42), varViewMonth + Value - Weekday(varViewMonth, StartOfWeek.Sunday) )
Each cell gets the correct date for that place in the grid, shifted so the top‑left cell is always a Sunday.
3. Configure Gallery Layout
Change these properties on gal_CalendarGrid:
| Property | Value |
|---|---|
| Fill | White |
| TemplatePadding | 0 |
| TemplateSize | Self.Height / 6 |
| WrapCount | 7 |
Without WrapCount = 7 the dates would appear in a single column. Now the gallery wraps after every 7 items, creating the grid.
4. Show the Day Number
Inside the gallery template, delete any existing label and insert a new Button named btn_DayNumber. Set its Text to:
Day(ThisItem.Value)
Style the button so it looks like a calendar cell:
// Border properties
BorderColor: RGBA(179, 179, 179, 1)
BorderThickness: 0.5
// Shape – circular for date appearance
RadiusBottom: 180
RadiusTop: Self.RadiusBottom
RadiusLeft: Self.RadiusBottom
RadiusRight: Self.RadiusBottom
// Size
Height: 40
Width: 40
// Colors
Color: If(
IsToday(ThisItem.Value), White,
Date(Year(ThisItem.Value), Month(ThisItem.Value), 1) = varViewMonth, Black,
LightGray
)
Fill: If(IsToday(ThisItem.Value), ColorValue("#0063B1"), Transparent)
// Hover feedback
HoverFill: ColorValue("#0063B120")
PressedFill: ColorValue("#0063B140")The Color formula makes:
- Today’s number white on a blue circle.
- Dates that belong to the current month black.
- Dates of adjacent months light gray.
5. Add Month/Year Header
Above the grid, add a Label named lbl_MonthYear. Set its Text to:
Text(varViewMonth, "[$-en-US]mmmm yyyy")
Make the font size 28, bold, and pick a color that matches your app theme.
6. Insert Weekday Headers
Add a new Horizontal Gallery above gal_CalendarGrid named gal_Weekdays. Set its Items to:
Calendar.WeekdaysShort()
Configure the gallery layout:
| Property | Value |
|---|---|
| Height | 45 |
| TemplatePadding | 0 |
| TemplateSize | Self.Width / 7 |
| ShowScrollbar | false |
Position it directly above the calendar grid (X and Y aligned). For each label inside this gallery, style it:
Color: White
Height: Parent.TemplateHeight
Text: ThisItem.Value
Width: Parent.TemplateWidth
Fill: ColorValue("#0063B1") // solid header backgroundThe weekdays now sit above each column, acting as a table header.
Navigation Controls
Allow users to browse months.
Previous Month
Insert a ChevronLeft icon (or a left arrow) to the left of the btn_Today. Set its OnSelect:
Set( varViewMonth, Date(Year(varViewMonth), Month(varViewMonth) - 1, 1) )
Next Month
Insert a ChevronRight icon to the right. OnSelect:
Set( varViewMonth, Date(Year(varViewMonth), Month(varViewMonth) + 1, 1) )
Test the calendar: pressing the arrows should move the month forward/back while keeping the grid in sync.
Click‑to‑Navigate from Adjacent Months
A nice behaviour is to jump to a different month when the user taps on a date that belongs to the previous or next month (as seen in many desktop calendars). Inside the btn_DayNumber button, add this OnSelect code:
Set( varViewMonth, Date(Year(ThisItem.Value), Month(ThisItem.Value), 1) )
Now clicking a gray date switches the calendar to that month.
Finishing Touches
-
Background image – Place an image behind all controls and set its ImagePosition to
FitorTile. This gives the app a polished look. -
Dark overlay – Insert a rectangle with
Fill = RGBA(0,0,0,0.3)behind the calendar controls to make text more readable over a busy background. -
Theme colors – Change the blue highlights to whatever matches your brand. All the formulas use
ColorValue("#0063B1")once, so you can replace it with a variable or theme colour.
Performance & Delegation Notes
- The
Sequence(42)andForAllrun entirely on the client – there is no delegation issue. - If you later connect to a SharePoint list for events, remember that
Filteragainst large datasets requires delegation‑friendly operators (e.g.,Date >= ... && Date < ...). Always pre‑filter by month range to avoid hitting the delegation limit. - Gallery template sizes should be calculated (e.g.,
Self.Height / 6) rather than hard‑coded so the layout adapts to different screen sizes.
Common Mistakes & Troubleshooting
| Mistake | Symptom | Fix |
|---|---|---|
Forgetting WrapCount = 7 | Dates appear in a single column. | Set gallery WrapCount to 7. |
Not resetting varViewMonth on OnVisible | Calendar shows an unexpected month when app starts. | Add the Set(...) code to the screen’s OnVisible. |
Using StartOfWeek.Monday for grid start | Grid starts on Monday instead of Sunday (if desired). | Use StartOfWeek.Sunday to keep Sunday first. |
Hard‑coded TemplateSize | Grid cells don’t resize on different screen heights. | Use Self.Height / 6 or Self.Height / 7 depending on layout. |
| Button for day number does not have transparent fill for non‑today cells | Gray background or unwanted highlight. | Ensure Fill = If(IsToday(...), ColorValue("#0063B1"), Transparent) and HoverFill / PressedFill use alpha colours. |
Where to Go Next
With the grid and navigation working, you’re ready to pull events from your data source and display them in each cell. That will be the subject of the next guide – we’ll populate the calendar with records from the LeaveRecords list, show employee names on each day, and allow managers to add new entries.
In the meantime, experiment with the grid styling: change the radius, add a subtle shadow, or animate the month‑year header. The more you tweak, the better you’ll understand the galleries.
References
- Matthew Devaney, “Make A Calendar In Power Apps – Part 1” (the original source that inspired this article).
- Microsoft Learn: Sequence function in Power Apps
- Microsoft Learn: Gallery control WrapCount property
Learn how small coding practices—like using descriptive names, flattening conditions, and simplifying logic—can make your apps easier to update and less error-prone.
Move past the gallery and discover the hidden patterns for validation, navigation, and smart submission handling in your data entry forms.
PowerShell unlocks admin capabilities that the Power Platform admin center simply doesn’t offer—from recovering deleted apps to blocking trial licenses. Here’s how to wield them safely.