Carousel
A dynamic card carousel with circular Previous and Next navigation buttons and a smooth 300 ms crossfade transition. Slide count adapts automatically to however many items are listed in galCarouselItems, no formula edits needed. The current slide number is stored in varCarouselIndex and displayed in a centered card. Inspired by the shadcn/ui Carousel component.
No settings required
This component works out of the box — no configuration needed.
How to Use
- Paste the YAML into Power Apps Studio (Ctrl+V). One GroupContainer (grpCarousel) is added with a hidden data gallery, two display galleries, a timer, and navigation buttons.
- The carousel starts at slide 1 automatically: no OnVisible initialisation needed (Coalesce handles blank state).
- To change the number of slides, edit ONLY galCarouselItems.Items (e.g. ["S","A","I","D","E"]); the slide count, wraparound logic, and content lookups all update automatically via CountRows(galCarouselItems.AllItems).
- To show real content instead of single letters, change galCarouselItems.Items to a table of records (e.g. a collection or [{title:"..."}, ...]) and update the .Value reference in lblSlide/lblSlideNext to the matching column name.
- Resize grpCarouselCard (Width/Height) to fit your content; adjust grpBtnPrev/grpBtnNext Y to re-centre the buttons vertically.
Problem Solved
Provides a carousel with a smooth 300 ms slide transition and a dynamic slide count. The current slide (galCurrent) exits in the direction of travel while the incoming slide (galNext) enters from the opposite side, driven by a hidden Timer inside the card container. All slide-count logic reads from a single hidden gallery (galCarouselItems) so adding or removing slides requires editing one property.
Integration
Animation uses four screen variables: varCarouselIndex (committed slide), varNavTarget (target slide), varNavDir (1 = next, -1 = prev), varAnimating (boolean). The Timer resets automatically after each transition so rapid clicks work correctly. Slide count is derived from CountRows(galCarouselItems.AllItems), never hardcoded.
YAML Code
- grpCarousel:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
Fill: =RGBA(0, 0, 0, 0)
BorderThickness: =0
DropShadow: =DropShadow.None
Height: =200
Width: =360
X: =20
Y: =20
Children:
- grpCarouselCard:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
Fill: =RGBA(255, 255, 255, 1)
BorderColor: =RGBA(226, 232, 240, 1)
BorderThickness: =1
DropShadow: =DropShadow.None
Height: =180
Width: =200
RadiusBottomLeft: =8
RadiusBottomRight: =8
RadiusTopLeft: =8
RadiusTopRight: =8
X: =80
Y: =10
Children:
- galCarouselItems:
Control: Gallery@2.15.0
Variant: Horizontal
Properties:
Items: =["S","A","I","D"]
Fill: =RGBA(0, 0, 0, 0)
Height: =1
ShowScrollbar: =false
TemplatePadding: =0
TemplateSize: =1
Visible: =false
Width: =1
X: =0
Y: =0
Children:
- lblCarouselItemTemplate:
Control: Label@2.5.1
Properties:
Text: =ThisItem.Value
Height: =1
Width: =1
X: =0
Y: =0
- tmrFade:
Control: Timer@2.1.0
Properties:
Duration: =300
OnTimerEnd: "=UpdateContext({varCarouselIndex: varNavTarget, varAnimating: false})"
Repeat: =false
Reset: =!varAnimating
Start: =varAnimating
Visible: =false
Height: =10
Width: =10
X: =0
Y: =0
- galCurrent:
Control: Gallery@2.15.0
Variant: Horizontal
Properties:
Items: =Filter(Sequence(CountRows(galCarouselItems.AllItems)), Value = Coalesce(varCarouselIndex, 1))
Fill: =RGBA(0, 0, 0, 0)
Height: =180
ShowScrollbar: =false
TemplatePadding: =0
TemplateSize: =200
Width: =200
X: =If(varAnimating, -varNavDir * Min(tmrFade.Value, 300) / 300 * 200, 0)
Y: =0
Children:
- lblSlide:
Control: Label@2.5.1
Properties:
Align: =Align.Center
VerticalAlign: =VerticalAlign.Middle
Color: =RGBA(15, 23, 42, 1)
Fill: =RGBA(0, 0, 0, 0)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Semibold
Height: =180
Size: =28
Text: =Index(galCarouselItems.AllItems, ThisItem.Value).Value
Width: =200
X: =0
Y: =0
- galNext:
Control: Gallery@2.15.0
Variant: Horizontal
Properties:
Items: =Filter(Sequence(CountRows(galCarouselItems.AllItems)), Value = Coalesce(varNavTarget, 1))
Fill: =RGBA(0, 0, 0, 0)
Height: =180
ShowScrollbar: =false
TemplatePadding: =0
TemplateSize: =200
Width: =200
X: =If(varAnimating, varNavDir * 200 * (1 - Min(tmrFade.Value, 300) / 300), 200)
Y: =0
Children:
- lblSlideNext:
Control: Label@2.5.1
Properties:
Align: =Align.Center
VerticalAlign: =VerticalAlign.Middle
Color: =RGBA(15, 23, 42, 1)
Fill: =RGBA(0, 0, 0, 0)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Semibold
Height: =180
Size: =28
Text: =Index(galCarouselItems.AllItems, ThisItem.Value).Value
Width: =200
X: =0
Y: =0
- grpBtnPrev:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
Fill: =RGBA(255, 255, 255, 1)
BorderColor: =RGBA(226, 232, 240, 1)
BorderThickness: =1
DropShadow: =DropShadow.None
Height: =36
Width: =36
RadiusBottomLeft: =18
RadiusBottomRight: =18
RadiusTopLeft: =18
RadiusTopRight: =18
X: =8
Y: =82
Children:
- icoPrev:
Control: Classic/Icon@2.5.0
Properties:
Color: =RGBA(15, 23, 42, 1)
Icon: =Icon.ChevronLeft
OnSelect: "=UpdateContext({varNavTarget: If(Coalesce(varCarouselIndex, 1) <= 1, CountRows(galCarouselItems.AllItems), Coalesce(varCarouselIndex, 1) - 1), varNavDir: -1, varAnimating: true})"
Height: =24
Width: =24
X: =6
Y: =6
- grpBtnNext:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
Fill: =RGBA(255, 255, 255, 1)
BorderColor: =RGBA(226, 232, 240, 1)
BorderThickness: =1
DropShadow: =DropShadow.None
Height: =36
Width: =36
RadiusBottomLeft: =18
RadiusBottomRight: =18
RadiusTopLeft: =18
RadiusTopRight: =18
X: =316
Y: =82
Children:
- icoNext:
Control: Classic/Icon@2.5.0
Properties:
Color: =RGBA(15, 23, 42, 1)
Icon: =Icon.ChevronRight
OnSelect: "=UpdateContext({varNavTarget: If(Coalesce(varCarouselIndex, 1) >= CountRows(galCarouselItems.AllItems), 1, Coalesce(varCarouselIndex, 1) + 1), varNavDir: 1, varAnimating: true})"
Height: =24
Width: =24
X: =6
Y: =6Implementation
Copies the customized component code directly to your clipboard. Use Ctrl+V in Power Apps Studio.
Something not pasting right? Troubleshooting guide