Skip to main content

CnGuardianHome

A first-class guardian/parent portal surface pattern, composed entirely from existing library primitives (NcCheckboxRadioSwitch, CnTabs/CnTab, NcButton, NcEmptyContent). No new dependency.

Every corpus competitor examined in learniq round 1 — including both open-source ones — ships a distinct parent-facing UI. learniq and portaliq currently build guardian surfaces ad hoc, per app, with no shared component (the M3(b) design-system request this component answers). CnGuardianHome is that shared shell: a children switcher, a "report absence" entry point, and three sections (feed, agenda, consent settings).

When to use​

Mount CnGuardianHome wherever a host app renders a guardian's own "home" view: a parent portal landing page, a dashboard tab for guardians, or a dedicated route. The component owns only the layout — it fetches nothing and knows nothing about OpenRegister, PortalContributionProvider, or any app's data model. Supply children as plain data (id, name, optional avatar) and fill the three section slots with your own data-bound widgets, for example a CnObjectListWidget for the feed and a calendar component for the agenda.

<CnGuardianHome
:children="children"
v-model:activeChildId="activeChildId"
@report-absence="openAbsenceForm">
<template #feed="{ child }">
<CnObjectListWidget :content="feedContentFor(child)" />
</template>
<template #agenda="{ child }">
<MyAgendaWidget :child-id="child.id" />
</template>
<template #consent="{ child }">
<MyConsentSettings :child-id="child.id" />
</template>
</CnGuardianHome>

Selecting a child​

activeChildId supports v-model. When it is unset, or names a child no longer present in children, the component falls back to the first child in the list and emits update:activeChildId — a guardian with one child never has to pick, and a host that does not manage selection at all still gets a sensible default. This also covers children arriving after an async fetch: the fallback re-evaluates whenever the children prop changes.

Sections stay mounted​

The feed / agenda / consent panels are built on CnTab, which keeps an inactive panel in the DOM (hidden, not destroyed) rather than tearing it down. Switching between sections never re-fires a host widget's own mounted() fetch.

Reference​

Props​

PropTypeDefaultDescription
childrenArray[]The guardian's children. Each entry should carry id and name; avatarUrl is optional.
activeChildIdString|NumbernullThe selected child's id (v-model-bindable). Falls back to the first entry in children when unset or stale.
showAbsenceActionBooleantrueWhether the "report absence" entry point renders in the header.
absenceLabelString''Override for the "report absence" button label.
feedLabelString''Override for the feed section's tab title.
agendaLabelString''Override for the agenda section's tab title.
consentLabelString''Override for the consent-settings section's tab title.
switcherLabelString''Accessible name for the children switcher (role="radiogroup").
sectionsLabelString''Accessible name for the feed/agenda/consent tab strip.

Slots​

SlotScopeDescription
empty—Overrides the "no children" empty state.
header-extra—Extra content rendered at the right of the header, before the "report absence" button.
feed{ child }The active child's feed.
agenda{ child }The active child's agenda/calendar.
consent{ child }The active child's consent settings.

Events​

EventPayloadDescription
update:activeChildIdstring|numberThe selected child changed, from the switcher or from the auto-selected-first-child fallback.
report-absenceobject (the active child)The guardian clicked "report absence".