Segmented Control

Material Design 3 segmented control for mutually exclusive options. Three display modes (Text, Icons, Both), three sizes, icon position control, per-option disable, and theme-aware styling. 21 controls, 10 properties.

cmpSegmentedControl.yaml

Import via Components → New component → Import from code → paste YAML

Preview

Installation

This component requires Modern controls to be enabled. Settings → Updates → Preview → Modern controls and themes

# In Power Apps Studio:
1. Components tab → New component → Import from code
2. Paste the full YAML definition
3. Add the component to any screen
4. Set Options table and DefaultValue

Usage

Basic text-only

cmpSegmentedControl.Options = Table(
    { Value: "list", Label: "List" },
    { Value: "grid", Label: "Grid" }
)
cmpSegmentedControl.DefaultValue = "list"
cmpSegmentedControl.DisplayMode = "Text"
cmpSegmentedControl.Size = "Medium"
cmpSegmentedControl.Theme = "Light"

Icon-only compact toolbar

// App.Formulas — define SVG icons once
svgList = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Cline x1='9' x2='21' y1='6' y2='6'/%3E%3Cline x1='9' x2='21' y1='12' y2='12'/%3E%3Cline x1='9' x2='21' y1='18' y2='18'/%3E%3Ccircle cx='4' cy='6' r='1.5' fill='%23666'/%3E%3Ccircle cx='4' cy='12' r='1.5' fill='%23666'/%3E%3Ccircle cx='4' cy='18' r='1.5' fill='%23666'/%3E%3C/svg%3E";
svgGrid = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Crect x='3' y='3' width='7' height='7' rx='1'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1'/%3E%3C/svg%3E";
svgTable = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Crect x='3' y='3' width='18' height='18' rx='2'/%3E%3Cpath d='M3 9h18M3 15h18M12 3v18'/%3E%3C/svg%3E";

cmpSegmentedControl.Options = Table(
    { Value: "list", Icon: svgList },
    { Value: "grid", Icon: svgGrid },
    { Value: "table", Icon: svgTable }
)
cmpSegmentedControl.DisplayMode = "Icons"
cmpSegmentedControl.Size = "Small"
cmpSegmentedControl.EqualWidth = false

Reading selection & handling changes

// Read the current value
Label1.Text = cmpSegmentedControl.SelectedValue

// Switch views based on selection
galListView.Visible = cmpSegmentedControl.SelectedValue = "list"
galGridView.Visible = cmpSegmentedControl.SelectedValue = "grid"

// React to changes via OnChange event
cmpSegmentedControl.OnChange = Switch(
    Self.SelectedValue,
    "list",  Set(varLayout, "vertical"),
    "grid",  Set(varLayout, "grid"),
    "table", Navigate(TableScreen)
)

Properties

Input

PropertyTypeDefault
Options

Table with Value, Label (optional), Icon (optional). No limit on option count.

Table3 items (list, grid, table)
DefaultValue

Initial selected value. Must match a Value in the Options table.

Text"list"
DisplayMode

"Text" (labels only), "Icons" (icons only), or "Both" (icon + label).

Text"Both"
IconPosition

"Left" or "Top". Only applies when DisplayMode is "Both".

Text"Left"
Size

"Small" (32px), "Medium" (40px), or "Large" (48px).

Text"Medium"
EqualWidth

When true, all option buttons share equal width. When false, icon-only mode auto-sizes.

Booleanfalse
Disabled

Disable entire component. All options become non-interactive.

Booleanfalse
Theme

"Light" or "Dark". Controls wrapper, selection indicator, and text colors.

Text"Light"

Output

PropertyTypeDescription
SelectedValueTextCurrently selected option value. Falls back to DefaultValue when varSelectedSegment is blank.

Events

EventDescription
OnChangeFires after the user selects a different option. Read SelectedValue inside this handler.

Implementation Details

Gallery-based architecture

The component uses a single horizontal gallery (galOptions) bound to the Options table via ForAll(Sequence(CountRows(Options))). Each template item contains a ManualLayout container for the selected fill, an AutoLayout container for centering icon + label, and a transparent button overlay for click handling. This supports any number of options without duplicated controls.

AutoLayout centering

Inside each gallery template, a cntContent AutoLayout container handles icon + label positioning with LayoutJustifyContent.Center and LayoutAlignItems.Center. No X/Y positioning math is needed. The layout direction flips between Horizontal (IconPosition = “Left”) and Vertical (IconPosition = “Top”) automatically.

Three display modes

Text: Only the label is visible, centered. Icons: Only the icon is visible, centered. Both: Icon and label are shown together. IconPosition controls layout — “Left” places the icon inline with the text, “Top” stacks them vertically with the icon above. Gap between icon and label scales with Size (Small = 4px, Medium = 6px, Large = 8px).

Auto-sizing for icon mode

When DisplayMode = "Icons" and EqualWidth = false, the component width scales dynamically: each option gets a square cell matching the component height (Small = 32px, Medium = 40px, Large = 48px per option, plus 6px wrapper padding). In all other modes the width is fixed at 400px.

Selection state

Selection is tracked via varSelectedSegment (set on button click). The SelectedValue output falls back to DefaultValue when the variable is blank (initial load). The selected option container shows a contrasting fill color (white on light, gray-700 on dark) and the label weight changes to Semibold.

Icon support

Icons are rendered as Image controls from SVG data URIs. Pass URL-encoded SVGs (e.g. data:image/svg+xml,%3Csvg...) in the Icon column. Define them as named formulas in App.Formulas for reuse across the app.

Examples

View switcher (Text mode)

cmpSegmentedControl.Options = Table(
    { Value: "list", Label: "List" },
    { Value: "grid", Label: "Grid" }
)
cmpSegmentedControl.DisplayMode = "Text"
cmpSegmentedControl.EqualWidth = true

galListView.Visible =
    cmpSegmentedControl.SelectedValue = "list"

Compact toolbar (Icon-only)

cmpSegmentedControl.Options = Table(
    { Value: "list", Icon: svgList },
    { Value: "grid", Icon: svgGrid },
    { Value: "table", Icon: svgTable }
)
cmpSegmentedControl.DisplayMode = "Icons"
cmpSegmentedControl.Size = "Small"
cmpSegmentedControl.EqualWidth = false
// svgList/svgGrid/svgTable = named formulas
// with SVG data URIs (see Usage above)

Navigation (Icon + Text)

// App.Formulas — define SVG icons once
svgList = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Cline x1='9' x2='21' y1='6' y2='6'/%3E%3Cline x1='9' x2='21' y1='12' y2='12'/%3E%3Cline x1='9' x2='21' y1='18' y2='18'/%3E%3Ccircle cx='4' cy='6' r='1.5' fill='%23666'/%3E%3Ccircle cx='4' cy='12' r='1.5' fill='%23666'/%3E%3Ccircle cx='4' cy='18' r='1.5' fill='%23666'/%3E%3C/svg%3E";
svgGrid = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Crect x='3' y='3' width='7' height='7' rx='1'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1'/%3E%3C/svg%3E";
svgTable = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Crect x='3' y='3' width='18' height='18' rx='2'/%3E%3Cpath d='M3 9h18M3 15h18M12 3v18'/%3E%3C/svg%3E";

cmpSegmentedControl.Options = Table(
    { Value: "list", Label: "List", Icon: svgList },
    { Value: "grid", Label: "Grid", Icon: svgGrid },
    { Value: "table", Label: "Table", Icon: svgTable }
)
cmpSegmentedControl.DisplayMode = "Both"
cmpSegmentedControl.IconPosition = "Left"
cmpSegmentedControl.Size = "Medium"

Data Schema

Options record

FieldTypeNotes
ValueTextRequired. Unique identifier returned by SelectedValue.
LabelTextOptional. Display text. Required when DisplayMode is "Text" or "Both".
IconTextOptional. URL-encoded SVG data URI. Required when DisplayMode is "Icons" or "Both". Define as named formulas in App.Formulas.

Architecture

7 controls — 1 wrapper + 1 gallery with 5 controls per template (2 containers, 1 image, 1 text, 1 button).

10 properties — 8 input, 1 output, 1 event.

Default size — 400 × 40px. Height varies by Size (32/40/48). Width scales dynamically in icon-only mode.

cmpSegmentedControl (400 × 40, or auto-width in icon mode)
└── cntWrapper (AutoLayout Horizontal, 3px padding, themed border + fill)
    └── galOptions (Horizontal Gallery, bound to Options via ForAll)
        └── [per item template]
            ├── cntOption (ManualLayout — selected fill + rounded corners)
            │   └── cntContent (AutoLayout — centers icon + label)
            │       ├── imgIcon  — SVG data URI, visible in Icons/Both modes
            │       └── lblText  — Label text, visible in Text/Both modes
            └── btnOption — transparent hit target → Set(varSelectedSegment, ThisItem.ItemValue); OnChange()

Selection: cntOption.Fill swaps to white (light) / gray-700 (dark)
Text: Weight → Semibold when selected, Regular otherwise
Layout: cntContent direction flips Horizontal ↔ Vertical based on IconPosition