Building a Weekly Calendar in Power Apps

In Power Apps, we can leverage a combination of controls and Power Fx functions to create a calendar. This is a common use case and one I’ve built several times for both clients and personal projects.

This article will go through the step-by-step process to build one for my wife’s business solution.

For the wife to book clients in for treatments, she’ll need a calendar of some kind. She needs to select any day to see appointments already scheduled, schedule new ones or re-arrange where required.

Looking around various mobile apps, she decided that if we could replicate Microsoft Teams, that would be ace:

Challenge accepted.

The build

We already have a header set up, which is a container control. We’ve added an image control for the business logo and set the Drop shadow property of the container to Regular. Our calendar functionality will live inside this container too:

OnStart logic

For the calendar to work, we’ll need some baseline logic to work with. These will be stored in global variables.

Firstly, we want to capture today’s date. This will stay fixed throughout the app’s session, as an easy way to always return the calendar back to the current day. Secondly, we’ll need a variable to store the date selected on the calendar. This will likely change during an app session but for the initial setting we can use the same logic:

				
					Concurrent(
    // Capture today's date
    Set(gvDateToday, Today()),
    // Use Today's date capture to set additional var
    Set(gvDateSelect, Today())
);
				
			

As per my previous post (when we created a menu component), my font sizes, colours and other config are also generated in OnStart. I’ll be referring to this for some settings later in this article, so if you want to follow along then I’d suggest adding this Power Fx to your OnStart as well. Feel free to change any of the settings for your app:

				
					Set(
    gvConfig,
    {
        Background: ColorValue("#FFFCF7"),
        Primary: ColorValue("#2B6B31"),
        LogoBase: ColorValue("#C4EBD4"),
        Negative: ColorValue("#CD5C5C"),
        FontText: Font.Lato,
        FontHeader: Font.'Lato Black',
        FontSizeDefault: 16,
        FontSizeHeader: 20
    }
);
				
			

Navigation logic

We’ll need logic for a fixed 7-day window that depends on today’s date. We also need to provide functionality to show future or previous weeks. The wife will have recurring clients who’ll book for the next month as soon as their current appointment has finished. 

At the same time, we also want quick navigation back to today’s date. We’re going to achieve this by adding 3 icons, each with their own OnSelect functionality.

I’ve inserted the following 3 icons & renamed them icoPreviousWeek, icoToday & icoNextWeek, respectively:

For each icon, I’ve updated the following properties:

Property Value
Color
gvConfig.Primary
Height
40
Width
40

For the OnSelect property of the icoToday icon, we’ll set a global variable called gvFirstDayOfTheWeek to reflect the 7-day block of the current week we’re in:

				
					// Set gvDateSelect to today
Set(
    gvDateSelect,
    gvDateToday
);
// Set gvFirstDayOfTheWeek to current week
Set(
    gvFirstDayOfTheWeek,
    Switch(
        Weekday(gvDateSelect),
        7,DateAdd(gvDateSelect,-6,TimeUnit.Days),
        6,DateAdd(gvDateSelect,-5,TimeUnit.Days),
        5,DateAdd(gvDateSelect,-4,TimeUnit.Days),
        4,DateAdd(gvDateSelect,-3,TimeUnit.Days),
        3,DateAdd(gvDateSelect,-2,TimeUnit.Days),
        2,DateAdd(gvDateSelect,-1,TimeUnit.Days),
        1,DateAdd(gvDateSelect,0,TimeUnit.Days),
        DateValue("01/01/2020")
    )
);
				
			

Hold down the ‘alt’ key and click on the icoToday icon. We need gvFirstDayOfTheWeek set with a value.

For the OnSelect property of the icoPreviousWeek icon, we need to reset gvFirstDayOfTheWeek so the 7-day view is the previous week:

				
					// Using gvFirstDayOfTheWeek, get the date 7 days ago
Set(
    gvFirstDayOfTheWeek,
    DateAdd(
        gvFirstDayOfTheWeek,
        -7,
        TimeUnit.Days
    )
)
				
			

For the OnSelect property of the icoNextWeek icon, we need to reset gvFirstDayOfTheWeek so the 7-day view is the next week:

				
					// Using gvFirstDayOfTheWeek, get the date in 7 days time
Set(
    gvFirstDayOfTheWeek,
    DateAdd(
        gvFirstDayOfTheWeek,
        7,
        TimeUnit.Days
    )
)
				
			

OnVisible logic

Every time my wife lands back on this screen, she wants to auto-defer back to today’s date within the current week. For that, we need to run the same logic that we’ve just added to the OnSelect property of the icoToday icon.

Instead of duplicating the code, we can cheat a bit! Select the screen from the left hand menu and access the OnVisible property:

We can use Power Fx to select the icoToday icon, which will mimic the action of a user clicking on it. As a result, it will run the Power Fx we already added in the OnSelect property:

				
					Select(icoToday)
				
			

Calendar gallery

To begin building the calendar, click on Insert and add a Blank Horizontal Gallery:
Adding a blank horizontal gallery to Power Apps

Update the following properties:

Property Value
Height
85
Template padding
Width
640

We always need an items property for a gallery, but we have no table or list to use here. That’s ok, we are going to use the Sequence function to create 7 rows,1 for each day of the week. Access the Items property of the gallery and add the following formula:

				
					Sequence(7,0)
				
			

To show an even spacing for 7 items, update the Template size property of the gallery to:

				
					Parent.Width / 7
				
			

If we add a label to the gallery for a test, we can see 7 items evenly spaced:

Remove the label and instead, add a button control to the gallery. Update the following properties:

Property Value
BorderColor
gvConfig.Primary
Border radius
30
Border thickness
1
Color
Color.Black
Fill
Color.Transparent
Font
gvConfig.FontText
Font size
gvConfig.FontSizeDefault
Height
50
Width
50
X
20
Y
24

With those changes we should have something like this:

With the formatting done, we need to update the Text property of the button. This needs to show the day number within the presented week. 

Update the Text property of the button with the following Power Fx:

				
					/* 
   Show day value based on gvFirstDayOfTheWeek,
   adding the no of days as per Gallery item no
   from initial Sequence function
*/
Day(
    DateAdd(
        gvFirstDayOfTheWeek,
        ThisItem.Value,
        TimeUnit.Days
    )
)
				
			

I’m writing this post on Saturday 1st July 2023. Therefore, we have a 1 for day 6 of the week and 26th June for day 1:

That’s cool, but how will the wife know what month she’s looking at? Even more so, when a single week view can show values for 2 different months.

Add a Label control to the gallery. Update the following properties:

Property Value
Font
gvConfig.FontText
Font size
gvConfig.FontSizeDefault
Height
20
Text alignment
Align center
Width
Parent.TemplateWidth
X
Y

For the Text property of the label, update with the following Power Fx:

				
					/* 
   Show first 3 letters of the month name value based 
   on gvFirstDayOfTheWeek, adding the no of days as per 
   Gallery item no from initial Sequence function
*/
Text(
    DateAdd(
        gvFirstDayOfTheWeek,
        ThisItem.Value,
        TimeUnit.Days
    ),
    "mmm"
)
				
			

Visually, we’re now in a good spot:

Selecting a date

If you remember our initial OnStart logic earlier, we set a global variable (gvDateSelect) to reflect the current date. This value will effectively be what’s written back to the Appointments table for the wife’s schedule. 

We’ll need this value to change depending on what day she’s selected from the calendar. Appointments are more likely to be made for a date in the future. 

To handle this, select the button in the calendar gallery. In the OnSelect property, replace Select(Parent) with the following Power Fx:

				
					// Update gvDateSelect with selected date
Set(
    gvDateSelect,
    DateAdd(
        gvFirstDayOfTheWeek,
        ThisItem.Value,
        TimeUnit.Days
    )
);
				
			

Weekdays gallery

To avoid any confusion, the wife also wants an idea of what day of the week the calendar entries relate to.

We can do this by adding another Blank Horizontal Gallery to the screen. In the Items property, add the following:

				
					Calendar.WeekdaysShort()
				
			

Update the following gallery properties:

Property Value
Height
30
Template padding
Template size
Parent.Width / 7
Width
Parent.Width

Once done, add a Label control to the gallery. Update the following label properties:

Property Value
Font
gvConfig.FontText
Font size
gvConfig.FontSizeDefault
Font weight
Semibold
Height
Parent.Height
Text
ThisItem.Value
Text alignment
Align center
Width
Parent.TemplateWidth

You should be left with something that looks like:

Conditional formatting

Lastly, she’d like a bit of formatting to highlight both the date selected and the current date.

In the calendar gallery, select the Button control and access the Fill property. Replace what’s there with the following Power Fx logic:

				
					With(
    {
        // Store result of DateAdd as a temp output
        tvCalendarDay: DateAdd(
            gvFirstDayOfTheWeek,
            ThisItem.Value,
            TimeUnit.Days
        )
    },
    If(
        // If date select matches temp output
        gvDateSelect = tvCalendarDay,
        gvConfig.Primary,
        // If date selected matches today
        Today() = tvCalendarDay,
        gvConfig.LogoBase,
        // If no conditions match
        Color.Transparent
    )
)
				
			

For the button’s Color property, update with the following Power Fx:

				
					If(
    // If date select matches, white, else black
    gvDateSelect = DateAdd(
        gvFirstDayOfTheWeek,
        ThisItem.Value,
        TimeUnit.Days
    ),
    Color.White,
    Color.Black
)
				
			

Testing

We need to test 2 things:

1 > gvDateSelect reflects the correct date, and
2 > we can cycle through previous and future weeks.

An easy way to do this is add a temporary label to the screen and set the Text property to gvDateSelect. Then, put the app into Play mode and interact:

Happy with progress so far. In the next article, we’ll extend the calendar experience to show available timeslots for the day selected.

What do you think?

Your email address will not be published. Required fields are marked *

5 Comments
  • Hunter White
    July 12, 2023

    Love this! Thanks for creating so much detail on how to achieve this!

    • Craig
      July 14, 2023

      No worries, Hunter. Thanks for the feedback!

  • Heather Perriam
    July 14, 2023

    This is great! Excited to see the next article.

  • Wije
    September 10, 2024

    Thank you.