• 4 min readPCF
PCF LeftNav (Canvas App)

A compact, collapsible left rail for Canvas Apps with JSON-driven items, sections, footer/profile, and full theming.
Live preview
Rodas Yonass HR
Core
Manage
RY
Rodas
Admin
ItemsJson (supports // & /* */ comments + trailing commas)
SelectedKey:
dashboard
IsExpanded:
true
Table Of Contents
A lightweight, themeable left navigation for Canvas Apps. JSON-powered items, built‑in icons (emoji/SVG/URL/
), sections, pinned footer/profile, and snap widths.Icon.*
Features
- 🚪 Docked / collapsible rail with smooth width snapping
- 📜 JSON-powered items (tolerates
&//
comments + trailing commas)/* … */
- 🎨 Built-in icons + Canvas
support + emoji/SVG/URLIcon.*
- 👁️ Per-item hide flag:
hideNavItem: true
- 🖌️ Theme dropdown presets + full custom JSON theme
- ♿ Accessible & responsive: focusable items, pinned header/footer, scrollable list
Inputs (Properties)
Property | Type | Default | Notes | Example |
---|---|---|---|---|
ItemsJson | Text |
| JSON array of nav items. Supports comments + trailing commas. | See samples |
Collapsed | Boolean |
| Initial collapsed state; host can toggle at runtime. |
|
Width | Number |
| Expanded (docked) width in px. |
|
CollapsedWidth | Number |
| Collapsed rail width (px). Clamped 40–200. |
|
ExpandedWidth | Number | Width | If omitted, uses Width. Must be > CollapsedWidth. |
|
Theme | Enum |
| light, dark, sky, sage, green, blue, custom |
|
ThemeJson | Text | (blank) | Only used when Theme = custom. JSON mapping CSS vars. | See examples |
HideHeader | Boolean |
| Hide entire brand row (title + hamburger). |
|
BrandLabel | Text |
| Header title when expanded. |
|
BrandIcon | Text | (blank) | Emoji, raw , image URL/data URI, or Canvas Icon.* name. | /
|
ActiveKey | Text | (blank) | Programmatic selection from host. If set, wins over user selection. |
|
Outputs
Output | Type | Notes |
---|---|---|
SelectedKey | Text | Last clicked item’s key. Ignored when ActiveKey is supplied. |
IsExpanded | Boolean | Current expanded state of the rail. |
Copy/Paste Setup
// Minimal ItemsJson example LeftNav.ItemsJson = JSON( Table( { key: "dashboard", label: "Dashboard", icon: "🏠" }, { type: "section", key: "sec-benefits", label: "Benefits" }, { key: "reports", label: "Reports", icon: "<svg viewBox='0 0 20 20' width='20' height='20'><path d='M4 2v16h12V6.4L13.6 2H4Z' fill='currentColor'/></svg>" }, { type: "footer", key: "settings", label: "Settings", icon: "⚙️" }, { type: "profile", key: "me", label: User().FullName, initials: "RY", role: "Admin" } ), JSONFormat.Compact ); // Suggested widths and theme LeftNav.CollapsedWidth = 64; LeftNav.ExpandedWidth = 320; LeftNav.Theme = "dark"; // Programmatic selection across screens If(!IsBlank(LeftNav.SelectedKey), Set(glbActiveKey, LeftNav.SelectedKey)); LeftNav.ActiveKey = glbActiveKey; If(IsBlank(glbActiveKey), Set(glbActiveKey, "dashboard"));
JSON Schema & Examples
Minimal
[ { "key": "dashboard", "label": "Dashboard", "icon": "dashboard" }, { "key": "reports", "label": "Reports", "icon": "Icon.ReportDocument" } ]
With sections, children, footer, and hide
[ { "type": "section", "label": "Core" }, { "key": "home", "label": "Home", "icon": "🏠" }, { "key": "people", "label": "People", "icon": "Icon.People", "children": [ { "key": "directory", "label": "Directory", "icon": "search" }, { "key": "reviews", "label": "Reviews", "icon": "reviews", "hideNavItem": true } ] }, { "type": "section", "label": "Manage" }, { "key": "jobs", "label": "Jobs", "icon": "job" }, { "key": "settings", "label": "Settings", "icon": "Icon.Settings", "footer": true }, { "type": "profile", "label": "Rodas", "initials": "RY", "role": "Admin" } ]
Theming
Presets
Choose from:
light
, dark
, sky
, sage
, green
, blue
.
Custom JSON
When Theme =
custom
, paste JSON. Example (Deep Slate):
{ "background": "#1e293b", "foreground": "#f1f5f9", "muted": "#94a3b8", "hover": "#334155", "border": "#475569", "accent": "#f97316", "selected": "#475569", "selectedForeground": "#ffffff", "selectedIcon": "#fb923c", "selectedIndicator": "#f97316" }
More presets: Sky, Sage, Green, Blue (see README for JSON snippets).
Troubleshooting
- Custom colors don’t apply → Ensure Theme =
and ThemeJson is valid JSON.custom
- Still looks light/dark → If Theme ≠
, presets override ThemeJson.custom
- Item won’t hide → Add
on the exact node."hideNavItem": true
- Hamburger/title overlap → Header reserves space; long titles will truncate.
- Selection flashes → Always bind ActiveKey globally.
- Repeat clicks → Use SelectPulse in OnChange; increments on every click.
Developer Notes
- Selected state is fully themeable via
,selected
,selectedForeground
,selectedIcon
.selectedIndicator
- If selected* keys are missing, falls back to
.accent
- Internal CSS vars:
,--ln-bg
,--ln-fg
,--ln-muted
,--ln-hover
,--ln-selected
,--ln-border
,--ln-accent
, plus selected overrides.--ln-section-fg
Download
- .msapp:
/downloads/pcf-leftnav.msapp
- GitHub:
https://github.com/rodasyonass/pcf-leftnav
Happy building!