How to Create Horizontal Scroll & Freeze Pane in PowerApps Canvas
Hi everyone,
Last week, I suddenly wanted to create a freeze pane in PowerApps Canvas to show my data, and guess what? I cannot find any solution in Youtube or any blogs that I want. So I think why should I create one to should anyone else who want the samething with me. So today I’d like to share how to build a PowerApps Canvas screen that mimics the Freeze Pane behavior in Excel while also supporting horizontal scrolling when you have many columns in your data table.
I. What is Freeze Pane?
In Excel, Freeze Pane is a feature that allows you to lock the first row and/or first column of a table. This way, the headers or key columns remain visible as you scroll.
PowerApps doesn’t provide this feature out of the box, but we can replicate it using a combination of layout containers and controls.
II. Creating a Table in PowerApps
The most common way to display tabular data in PowerApps is by using the Gallery control. There are three types of galleries:
- Vertical gallery
- Horizontal gallery
- Flexible height vertical gallery
In this guide, we’ll use the Vertical Gallery, which is ideal for structured table-style layouts.
III. The Problem with Many Columns
When your dataset has many columns, some controls (like The blue column in below pic) may overflow the visible area and won’t be displayed.
A common approach is to wrap all gallery items inside a horizontal container and set its OverflowX
to Scroll
.
However, this results in each gallery item having its own independent scroll bar, which is not ideal from a user experience standpoint.
IV. Proper Horizontal Scrolling Using a Slider
Instead of scrolling each item individually, a better approach is to place all the columns inside a container and control its X position with a shared Slider. This ensures all rows are scrolled in sync.
What the user sees in the gallery is the area defined by X:0, Y:0
to TemplateWidth:TemplateHeight
. So, if a component inside the gallery is positioned outside of this visible area, it won't be shown to the user.
We can take advantage of this behavior by hiding the leftmost columns (placing them outside the visible area), allowing more space to show additional columns on the right.
Sample setup:
V. Implementing Freeze Pane
To mimic the Freeze Pane behavior, we need to fix two things:
1. Freeze First Column
- Move the first column out of the horizontally scrollable container but still in the gallery row.
- Position it on the left of the row, fixed position.
- Update the scrollable container's
X
property as follows:
X = lblFreezeColumn.Width - Slider1.Value
With lblFreeColumn is the column that you moved out of the container. With this, your table have a fixed column and can horizontal scroll other columns
2. Add Header Row
Our table needs to have a header. This is quite simple:
- Create a separate container for the header row above the gallery.
- Copy components from the gallery to that container. You will get some errors if you reference some gallery contexts; just replace that to remove issues.
VI. Making the Slider Look Like a Native Scrollbar
The default Slider control in PowerApps doesn't look or behave like a native scrollbar, which may create UI inconsistency. Here’s a trick to replicate a scrollbar experience using scrollable containers.
Steps:
-
Add a horizontal container below the gallery.
- Set its Height to
12px
.
- Set its Height to
-
Inside this container, add another horizontal container:
- Also set its Height to
12px
. - Set its OverflowX property to
Scroll
.
- Also set its Height to
Name the inner container some
thing like `conHorizontalScroll`.
Set the Width of
conHorizontalScroll
to:
= conScrollableColumnsTitle.Width + 12
- Wherever you're currently using -Slider1.Value to control horizontal movement, replace it with:
+conHorizontalScroll.X
Why Does This Work?
In PowerApps, when a container is scrollable (either horizontal or vertical), its child elements' X and Y values automatically shift in the opposite direction of the scroll.
This means you can directly use the changing X position of a child element as a scroll reference—no need for a separate slider.
This method gives you better control over the scroll experience and integrates more cleanly with the app’s UI.
The code:
Screens:
Freeze Pane Screen:
Properties:
Fill: =RGBA(255, 255, 255, 1)
LoadingSpinnerColor: =RGBA(0, 120, 212, 1)
Children:
- Container3:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
Height: =Parent.Height
LayoutDirection: =LayoutDirection.Vertical
LayoutGap: =12
Width: =Parent.Width
Children:
- Header1:
Control: Header@0.0.44
Properties:
Fill: =RGBA(214, 221, 224, 1)
Logo: ='powerapp-2020-icon-1024x1024-1'
Style: ='Header.Style'.Neutral
Title: ="AWESOME APPLICATION "
- conMainGal:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
LayoutDirection: =LayoutDirection.Vertical
Children:
- conTitle:
Control: GroupContainer@1.3.0
Variant: ManualLayout
Properties:
FillPortions: =0
Height: =60
Children:
- conScollColumns_Title:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
BorderColor: =RGBA(214, 221, 224, 1)
BorderThickness: =1
Height: =60
LayoutDirection: =LayoutDirection.Horizontal
RadiusBottomLeft: =0
RadiusBottomRight: =0
RadiusTopLeft: =0
RadiusTopRight: =0
Width: =3000
X: =conFreezeColumnsTitle.Width + conHorizonScroll.X
Y: =1
Children:
- TextCanvas3_3:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(166, 215, 153, 1)
FillPortions: =1
Size: =18
Text: ="Sample Text"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Semibold
- TextCanvas3_4:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(255, 184, 174, 1)
FillPortions: =1
Size: =18
Text: ="Sampleling Text"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Semibold
- TextCanvas3_6:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(180, 214, 250, 1)
FillPortions: =1
Size: =18
Text: ="Sampleling Text"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Semibold
- TextCanvas3_8:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(156, 99, 207, 0.9)
FillPortions: =1
Size: =18
Text: ="Sampleling Text"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Semibold
- TextCanvas3_9:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(180, 214, 250, 1)
FillPortions: =1
Size: =18
Text: ="Sampleling Text"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Semibold
- conFreezeColumnsTitle:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
BorderColor: =RGBA(214, 221, 224, 1)
BorderThickness: =1
Fill: =RGBA(174, 208, 221, 1)
Height: =60
LayoutDirection: =LayoutDirection.Horizontal
RadiusBottomLeft: =0
RadiusBottomRight: =0
RadiusTopLeft: =0
RadiusTopRight: =0
Y: =1
Children:
- TextCanvas3_5:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
FillPortions: =1
Size: =18
Text: ="Title"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Semibold
- galMainGal:
Control: Gallery@2.15.0
Variant: Vertical
Properties:
BorderColor: =RGBA(245, 245, 245, 1)
Items: =Table(CustomGallerySample,CustomGallerySample,CustomGallerySample)
TemplatePadding: =0
TemplateSize: =100
Children:
- conScollColumns:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
BorderColor: =RGBA(214, 221, 224, 1)
BorderThickness: =1
Height: =Parent.TemplateHeight
LayoutDirection: =LayoutDirection.Horizontal
RadiusBottomLeft: =0
RadiusBottomRight: =0
RadiusTopLeft: =0
RadiusTopRight: =0
Width: =conScollColumns_Title.Width
X: =500 + conHorizonScroll.X
Children:
- TextCanvas3_1:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(166, 215, 153, 1)
FillPortions: =1
Text: =ThisItem.SampleText
VerticalAlign: =VerticalAlign.Middle
- TextCanvas3_2:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(255, 184, 174, 1)
FillPortions: =1
Text: =ThisItem.SampleHeading &" " & ThisItem.SampleText
VerticalAlign: =VerticalAlign.Middle
- TextCanvas3_7:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(180, 214, 250, 1)
FillPortions: =1
Text: =ThisItem.SampleHeading &" " & ThisItem.SampleText
VerticalAlign: =VerticalAlign.Middle
- TextCanvas3_10:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(156, 99, 207, 0.9)
FillPortions: =1
Text: ="Sampleling Text"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Regular
- TextCanvas3_11:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
Fill: =RGBA(180, 214, 250, 1)
FillPortions: =1
Text: ="Sampleling Text"
VerticalAlign: =VerticalAlign.Middle
Weight: ='TextCanvas.Weight'.Regular
- conFreezeColumns:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
BorderColor: =RGBA(214, 221, 224, 1)
BorderThickness: =1
Fill: =RGBA(174, 208, 221, 1)
Height: =Parent.TemplateHeight
LayoutDirection: =LayoutDirection.Horizontal
RadiusBottomLeft: =0
RadiusBottomRight: =0
RadiusTopLeft: =0
RadiusTopRight: =0
Width: =conFreezeColumnsTitle.Width
Children:
- TextCanvas3:
Control: Text@0.0.51
Properties:
Align: ='TextCanvas.Align'.Center
AlignInContainer: =AlignInContainer.Stretch
FillPortions: =1
Text: =ThisItem.SampleHeading
VerticalAlign: =VerticalAlign.Middle
- Container10:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
FillPortions: =0
Height: =12
LayoutDirection: =LayoutDirection.Vertical
LayoutOverflowX: =LayoutOverflow.Scroll
Children:
- conHorizonScroll:
Control: GroupContainer@1.3.0
Variant: AutoLayout
Properties:
AlignInContainer: =AlignInContainer.Start
FillPortions: =0
Height: =12
LayoutDirection: =LayoutDirection.Horizontal
LayoutMinWidth: =2000
Width: =conFreezeColumnsTitle.Width + conScollColumns_Title.Width + 12
So that's how to make a freeze pane in PowerApps Canvas. If you would like to get notified every new blog, you can subscribe below.
Top comments (0)