Choice Card
A radio-selectable list of bordered choice cards: a legend + description header, then options each shown with a title, description, and radio indicator, with a highlighted border on the selected card. Inspired by the shadcn/ui Field/FieldSet Choice Card composition.
How to Use
- On the Settings tab, edit the legend/description and the Options list: each option has a Title and an optional Description. The Preview tab and the copyable YAML update together.
- Paste the YAML into Power Apps Studio (Ctrl+V). One GroupContainer (conChoiceCard) is added. Everything nests inside it via Vertical AutoLayout, so it reflows correctly if you resize it.
- Click a card to select it: the selected card gets a darker border and a filled radio dot; nothing is pre-selected by default. Selection is stored as plain text in varChoiceCardSelected (the option's Title).
- Each card exactly fills its Gallery template slot (TemplateSize:=80, with the row Height self-tracking as Parent.TemplateHeight) instead of using TemplatePadding (which was tried first and caused clipping); change TemplateSize alone to adjust card size (also bump the description/text-column Heights to match if you make it noticeably smaller, or content may clip); cards render back-to-back with no gap between them, separated only by their own borders. Inside each card, the title/description column and the radio indicator are arranged with a Horizontal AutoLayout row (tight padding + a gap, not hand-placed X/Y); only the card's own hit-target overlay and the tiny radio ring+dot pair stay ManualLayout, since those two genuinely need to overlap other content.
- The description line has room for about 3 wrapped lines. Labels wrap by default in Power Apps once given enough Height, but longer text will clip; keep descriptions short for the cleanest result.
- galChoiceCardList.Height grows automatically with the number of options, up to 4 visible cards (320px), capped there (ShowScrollbar:=false, so there's no scroll affordance past the cap). conChoiceCard's own Height tracks the Gallery's live height too, so the whole card resizes with the option count. No OnVisible initialisation needed.
Problem Solved
Provides a radio-selectable list of richer, self-describing options (title + description per choice, shown as a bordered card), a common pattern for plan/tier/environment pickers, which Power Apps has no native equivalent for (the closest native control, Classic/RadioButton, has no per-option rich content).
Integration
The website builds a Power Fx array-of-records literal from your Options list and bakes it into the copied YAML as galChoiceCardList.Items (columns: Label, Description). Read the chosen option from varChoiceCardSelected. To swap the option list for a real data source later, replace the array in galChoiceCardList.Items with a table/collection reference that has matching Label/Description columns.
YAML Code
- conChoiceCard:
Control: GroupContainer@1.5.0
Variant: AutoLayout
Properties:
DropShadow: =DropShadow.None
Height: =60 + galChoiceCardList.Height
LayoutAlignItems: =LayoutAlignItems.Stretch
LayoutDirection: =LayoutDirection.Vertical
LayoutGap: =12
Width: =340
X: =20
Y: =20
Children:
- lblChoiceCardLegend:
Control: Label@2.5.1
Properties:
AlignInContainer: =AlignInContainer.Stretch
Color: =RGBA(15, 23, 42, 1)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Semibold
Height: =20
LayoutMinWidth: =0
Text: ="Delivery Method"
- lblChoiceCardDesc:
Control: Label@2.5.1
Properties:
AlignInContainer: =AlignInContainer.Stretch
Color: =RGBA(100, 116, 139, 1)
Font: =Font.'Open Sans'
Height: =16
LayoutMinWidth: =0
Size: =10
Text: ="Choose how you'd like to receive your order."
- galChoiceCardList:
Control: Gallery@2.15.0
Variant: Vertical
Properties:
DelayItemLoading: =false
FillPortions: =0
Height: =Min(Self.AllItemsCount * 80, 320)
Items: =[{Label:"Standard Shipping",Description:"Delivered in 5-7 business days, at no extra cost."}, {Label:"Express Shipping",Description:"Delivered in 1-2 business days for a small fee."}]
LayoutMinWidth: =0
ShowScrollbar: =false
TemplatePadding: =0
TemplateSize: =80
Width: =340
Children:
- conChoiceCardRow:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
DropShadow: =DropShadow.None
Height: =Parent.TemplateHeight
Width: =Parent.TemplateWidth
Children:
- imgChoiceCardSelectedBg:
Control: Image@2.2.3
Properties:
Fill: =If(ThisItem.Label = varChoiceCardSelected, RGBA(248, 250, 252, 0.7), RGBA(0, 0, 0, 0))
Height: =Parent.Height
Image: =Blank()
RadiusBottomLeft: =8
RadiusBottomRight: =8
RadiusTopLeft: =8
RadiusTopRight: =8
Width: =Parent.Width
- conChoiceCardContent:
Control: GroupContainer@1.5.0
Variant: AutoLayout
Properties:
DropShadow: =DropShadow.None
Height: =Parent.Height
LayoutAlignItems: =LayoutAlignItems.Center
LayoutDirection: =LayoutDirection.Horizontal
LayoutGap: =12
PaddingBottom: =6
PaddingLeft: =16
PaddingRight: =16
PaddingTop: =6
Width: =Parent.Width
Children:
- conChoiceCardTextCol:
Control: GroupContainer@1.5.0
Variant: AutoLayout
Properties:
AlignInContainer: =AlignInContainer.Center
DropShadow: =DropShadow.None
Height: =64
LayoutAlignItems: =LayoutAlignItems.Stretch
LayoutDirection: =LayoutDirection.Vertical
LayoutGap: =4
LayoutJustifyContent: =LayoutJustifyContent.Center
LayoutMinWidth: =0
Children:
- lblChoiceCardTitle:
Control: Label@2.5.1
Properties:
AlignInContainer: =AlignInContainer.Stretch
Color: =RGBA(15, 23, 42, 1)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Semibold
Height: =18
LayoutMinWidth: =0
Size: =11
Text: =ThisItem.Label
- lblChoiceCardDescription:
Control: Label@2.5.1
Properties:
AlignInContainer: =AlignInContainer.Stretch
Color: =RGBA(100, 116, 139, 1)
Font: =Font.'Open Sans'
Height: =42
LayoutMinWidth: =0
Size: =10
Text: =ThisItem.Description
VerticalAlign: =VerticalAlign.Top
- conChoiceCardRadioWrap:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
AlignInContainer: =AlignInContainer.Center
DropShadow: =DropShadow.None
FillPortions: =0
Height: =20
LayoutMinWidth: =0
Width: =20
Children:
- imgChoiceCardRadioRing:
Control: Image@2.2.3
Properties:
BorderColor: =If(ThisItem.Label = varChoiceCardSelected, RGBA(15, 23, 42, 1), RGBA(203, 213, 225, 1))
BorderThickness: =2
Fill: =RGBA(255, 255, 255, 1)
Height: =20
Image: =Blank()
RadiusBottomLeft: =10
RadiusBottomRight: =10
RadiusTopLeft: =10
RadiusTopRight: =10
Width: =20
- imgChoiceCardRadioDot:
Control: Image@2.2.3
Properties:
Fill: =RGBA(15, 23, 42, 1)
Height: =10
Image: =Blank()
RadiusBottomLeft: =5
RadiusBottomRight: =5
RadiusTopLeft: =5
RadiusTopRight: =5
Visible: =ThisItem.Label = varChoiceCardSelected
Width: =10
X: =5
Y: =5
- btnChoiceCardItemHit:
Control: Classic/Button@2.2.0
Properties:
Align: =Align.Left
BorderColor: =If(ThisItem.Label = varChoiceCardSelected, RGBA(15, 23, 42, 1), RGBA(226, 232, 240, 1))
BorderThickness: =1
Color: =RGBA(0, 0, 0, 0)
DisabledBorderColor: =RGBA(226, 232, 240, 1)
Fill: =RGBA(0, 0, 0, 0)
FocusedBorderColor: =RGBA(226, 232, 240, 1)
FocusedBorderThickness: =1
Font: =Font.'Open Sans'
Height: =Parent.Height - 4
HoverBorderColor: =RGBA(148, 163, 184, 1)
HoverColor: =RGBA(0, 0, 0, 0)
HoverFill: =RGBA(0, 0, 0, 0)
OnSelect: =Set(varChoiceCardSelected, ThisItem.Label)
PressedBorderColor: =RGBA(148, 163, 184, 1)
PressedFill: =RGBA(0, 0, 0, 0)
RadiusBottomLeft: =8
RadiusBottomRight: =8
RadiusTopLeft: =8
RadiusTopRight: =8
Text: =""
Width: =Parent.Width - 4
X: =(Parent.Width - Self.Width)/2
Y: =(Parent.Height - Self.Height)/2Implementation
Copies the customized component code directly to your clipboard. Use Ctrl+V in Power Apps Studio.
Something not pasting right? Troubleshooting guide