Ranked horizontal bar list with auto-scaling, palette color cycling, light/dark theme, skeleton loading state, empty state, and click events. Built entirely with native Power Apps controls — no SVG, no Image hacks.
By Category
Current stock value
This component requires Modern controls to be enabled. Settings → Updates → Preview → Modern controls and themes
# In Power Apps Studio:
1. Open the Components tab in the left panel
2. Click "New component" → "Import from code (YAML)"
3. Paste the full cmpBarList YAML and save
4. Add the component to any screen from the Insert panel
5. Set the Data property to your collection or Table() literalImportant: Always load data into a named collection via App.OnStart before binding to Data. Passing a collection populated in OnVisible will render an empty component on first load because the component evaluates before OnVisible finishes. Static Table() literals are always safe to pass directly.
A fully wired test harness — component already included. Paste, click Initialize Test Data, and every property is live.
By Category
Current stock value
cmpBarList.Data = Table(
{Label: "Electronics", Value: 84200, isHidden: false},
{Label: "Hardware", Value: 61500, isHidden: false},
{Label: "Safety", Value: 48300, isHidden: false}
)
cmpBarList.Title = "By Category"
cmpBarList.Subtitle= "Current stock value"// App.OnStart — shape data once
ClearCollect(
colCategoryTotals,
AddColumns(
GroupBy(Inventory, "Category", "Items"),
Label, Category,
Value, Sum(Items, UnitValue),
Subtitle, CountRows(Items) & " items",
isHidden, false
)
);
// Screen — bind to component
cmpBarList.Data = colCategoryTotals
cmpBarList.ValueFormat = "Currency"
cmpBarList.ShowRowSubtitle = truecmpBarList.Theme = "Dark"
cmpBarList.OnBarClick = Set(gSelectedCategory, ClickedItem.Label)
// Read selected item reactively anywhere on screen
cmpBarList.SelectedItem.Label
cmpBarList.SelectedItem.BarValuecmpBarList.IsLoading = varIsLoading
cmpBarList.Data = colCategoryTotals
// In App.OnStart:
Set(varIsLoading, true);
ClearCollect(colCategoryTotals, Inventory);
Set(varIsLoading, false)cmpBarList.Data = colFilteredResults
cmpBarList.EmptyMessage = "No items match your filter"| Property | Type | Default |
|---|---|---|
DataTable of rows. Required columns: Label (Text), Value (Number), isHidden (Boolean). Optional: Subtitle (Text). | Table | 7-row sample |
TitleCard heading text. | Text | "By Category" |
SubtitleMuted subheading below the title. Hidden when blank. | Text | "Current stock value" |
ValueFormat"Currency" ($84.2K), "Number" (84,200), "Percent" (84.2%), "Auto" (abbreviate, no symbol). | Text | "Currency" |
Theme"Light" or "Dark". Switches the active color block in StyleConfig. | Text | "Light" |
ShowRowSubtitleShow the per-row Subtitle text beneath each label. Increases row height from 44 to 60px. | Boolean | false |
IsLoadingWhen true, replaces data rows with skeleton placeholder bars. Row count matches Data. | Boolean | false |
EmptyMessageText shown when Data is empty or all rows are hidden. Customize per screen context — e.g. "No items match your filter". | Text | "No data" |
PaletteAuto-cycling bar colors. Table with a single Color column. Values are hex strings without the leading #. | Table | 7-color default |
StyleConfigRecord with light and dark sub-records for all color tokens, plus spacing, typography, and radius values. | Record | See source |
| Property | Type | Description |
|---|---|---|
SelectedItem | Record | The last tapped row. Fields: Label, BarValue, SubtitleSafe, BarColor. Updates reactively — no need to capture in OnBarClick. |
| Event | Parameter | Description |
|---|---|---|
OnBarClick | ClickedItem (Record) | Fires when a row is tapped. ClickedItem contains the same fields as SelectedItem: Label, BarValue, SubtitleSafe, BarColor. |
| Field | Type | Required | Notes |
|---|---|---|---|
| Label | Text | Yes | Row label shown above the bar. |
| Value | Number | Yes | Numeric value. Determines bar width proportionally. Supports negatives and zero — both render a minimum 2px bar. |
| Subtitle | Text | No | Secondary line below the label. Shown when ShowRowSubtitle = true. |
| isHidden | Boolean | No | When true, the row is filtered out of both the data and skeleton galleries. |
By Category
Current stock value
cmpBarList.Theme = "Light"
cmpBarList.ValueFormat = "Currency"
cmpBarList.Title = "By Category"By Category
Current stock value
Laptops, monitors, cables
Hand tools, power tools
PPE, helmets, gloves
Boxes, tape, wrap
Chemicals, equipment
Paper, pens, binders
Mechanical, electrical
cmpBarList.Theme = "Dark"
cmpBarList.ShowRowSubtitle = true
cmpBarList.ValueFormat = "Currency"By Category
Current stock value
No items match your filter
Nothing to display
cmpBarList.Data = colFilteredResults
cmpBarList.EmptyMessage = "No items match your filter"Unlike SVG-based chart components, every element is a real Power Apps control —ModernText for labels and values,Classic/Button for track and fill bars. Theme switching is fully reactive with no SVG caching issues.
Max value is computed once in a hidden zero-heightlblBarListMax label outside the gallery, avoiding the galBarRows.AllItems pattern which causes division-by-zero errors on container resize. Fill width usesIfError(Round(Max(2, value / Max(1, Value(lblBarListMax.Text)) * width), 0), 2).
The gallery Items formula usesForAll(Sequence(n)) to inject a row index, then Mod(index - 1, paletteCount) + 1 to cycle. Colors are stored as hex strings without # and converted at render time via ColorValue("#" & ThisItem.BarColor).
When IsLoading = true, the data gallery hides and a skeleton gallery renders usingSequence(CountRows(Filter(Data, ...))). Skeleton bar widths use Mod() to stagger lengths so rows look naturally varied.
When Data is empty or all rows haveisHidden: true, a centered empty state renders with the EmptyMessage text. The card maintains a minimum height of 120px so it doesn‘t collapse. The empty state is hidden when IsLoading = true.
Bars are always sorted descending by value — the sort is baked into the Items formula and not currently configurable. No tooltips on hover (native controls don‘t support pointer events in gallery templates on mobile).
18 controls — all native. No Image controls, no SVG data URIs.
12 properties — 10 input, 1 output, 1 event.
Default size — App.Width × auto-height. Height is computed from row count and row height token, with a 120px minimum for the empty state.
cmpBarList (App.Width × auto-height)
└── conBarListCard (GroupContainer, ManualLayout)
├── lblBarListMax hidden label — holds Max(Data, Value) as text
├── txtBarListTitle ModernText — card title
├── txtBarListSubtitle ModernText — card subtitle
├── galBarListRows Gallery (Vertical, TemplateSize=44|60, Visible=!IsLoading)
│ └── conBarListRow GroupContainer per row
│ ├── txtBarListLabel ModernText — row label
│ ├── txtBarListValue ModernText — formatted value (right-aligned)
│ ├── txtBarListRowSub ModernText — row subtitle (conditional)
│ ├── btnBarListTrack Button — gray track background
│ ├── btnBarListFill Button — colored bar fill
│ └── btnBarListOverlay Button — transparent click target
├── galBarListSkeleton Gallery (Visible=IsLoading)
│ └── conBarListSkeletonRow
│ ├── btnBarListSkelLabel placeholder pill
│ ├── btnBarListSkelValue placeholder pill
│ └── btnBarListSkelBar placeholder bar
└── conBarListEmpty GroupContainer (Visible=empty && !IsLoading)
├── txtBarListEmptyTitle ModernText — EmptyMessage text
└── txtBarListEmptySub ModernText — "Nothing to display"One email when something new ships. Unsubscribe anytime.
Use the toolbar to format · or type markdown directly