Rodas Yonass
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

A lightweight, themeable left navigation for Canvas Apps. JSON-powered items, built‑in icons (emoji/SVG/URL/

Icon.*
), sections, pinned footer/profile, and snap widths.

Features

  • 🚪 Docked / collapsible rail with smooth width snapping
  • 📜 JSON-powered items (tolerates
    //
    &
    /* … */
    comments + trailing commas)
  • 🎨 Built-in icons + Canvas
    Icon.*
    support + emoji/SVG/URL
  • 👁️ Per-item hide flag:
    hideNavItem: true
  • 🖌️ Theme dropdown presets + full custom JSON theme
  • ♿ Accessible & responsive: focusable items, pinned header/footer, scrollable list

Inputs (Properties)

PropertyTypeDefaultNotesExample
ItemsJsonText
[]
JSON array of nav items. Supports comments + trailing commas.See samples
CollapsedBoolean
false
Initial collapsed state; host can toggle at runtime.
true
WidthNumber
280
Expanded (docked) width in px.
300
CollapsedWidthNumber
56
Collapsed rail width (px). Clamped 40–200.
64
ExpandedWidthNumberWidthIf omitted, uses Width. Must be > CollapsedWidth.
320
ThemeEnum
light
light, dark, sky, sage, green, blue, custom
custom
ThemeJsonText(blank)Only used when Theme = custom. JSON mapping CSS vars.See examples
HideHeaderBoolean
false
Hide entire brand row (title + hamburger).
true
BrandLabelText
"App"
Header title when expanded.
"Rodas HR"
BrandIconText(blank)Emoji, raw
<svg>
, image URL/data URI, or Canvas Icon.* name.
"💼"
/
"Icon.People"
ActiveKeyText(blank)Programmatic selection from host. If set, wins over user selection.
"dashboard"

Outputs

OutputTypeNotes
SelectedKeyTextLast clicked item’s key. Ignored when ActiveKey is supplied.
IsExpandedBooleanCurrent 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 =
    custom
    and ThemeJson is valid JSON.
  • Still looks light/dark → If Theme ≠
    custom
    , presets override ThemeJson.
  • Item won’t hide → Add
    "hideNavItem": true
    on the exact node.
  • 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
    ,
    --ln-section-fg
    , plus selected overrides.

Download

  • .msapp:
    /downloads/pcf-leftnav.msapp
  • GitHub:
    https://github.com/rodasyonass/pcf-leftnav

Happy building!

PCF LeftNav (Canvas App) — Canvas Components