Widget info Input contract โ
Widget info ยท developer handover
Metric Insight (Value Highlight)
One headline metric with its count qualifier, plus a lens ranking (home), cohort distribution and data-table view, switched by the footer toggle.
Live example
the Pupil Premium metric fromVALUE_METRICS โ fully interactive, try the ๐ / Distribution / Data toggleStudent Demographics +1.8pp
Pupil Premium Students
The percentage of pupils eligible for Pupil Premium funding โ a marker of a more disadvantaged intake.39.4%99 of 251 students
Complexity rankingHigher = more challenging context. A higher percentile ranks this organisation nearer "More complex" within the comparison cohort.
64thpercentile
Higher = more challenging context.
Dependencies
Component: app/components/widgets/ValueHighlight.vue
Explicit imports
Imported at the top of the component.
LENSESโ~/data/widgetsApp-level config: lens colour and the interpretation line ('Higher = more challenging context') shown on every view. Stays in the app โ not API data.ValueMetric (type)โ~/data/widgetsThe input contract โ the shape the API response must be mapped into.SemanticColor, WidgetMode (types)โ~/utils/typesColour-token union and the "desktop" | "distribution" | "data" mode union.valenceColor, trendToneโ~/utils/identityLens-aware colouring: variant mode colours by valence (good/bad), and the delta chip colours by whether the trend direction is favourable for this lens.
Auto-imported components (Nuxt)
No import lines โ Nuxt resolves these from app/components/widgets/parts/ (flat names, pathPrefix: false). A port to another stack must import them explicitly.
WidgetShellโwidgets/parts/WidgetShell.vueShared chrome: family header, definition tooltip, delta chip, and the home/Distribution/Data mode toggle in the footer.Headlineโwidgets/parts/Headline.vueThe big value plus its qualifier โ renders "99 of 251 students" (or a per-pupil figure) beside the headline.RankingPanelโwidgets/parts/RankingPanel.vueHome view: the tinted '64th percentile' lens ranking panel.PercentileLineโwidgets/parts/PercentileLine.vueDistribution view: the percentile read-out line above the histogram.Histogramโwidgets/parts/Histogram.vueDistribution view: the cohort distribution bars with this organisation's position marked.DataGridโwidgets/parts/DataGrid.vueData view: the cohort / value / percentile table (also renders the interpretation line on that view).
Framework APIs
Auto-imported by Nuxt; from 'vue' in a plain Vue build.
ref, computedโvueInternal state only โ the active mode and the resolved comparison cohort. None of it needs the API.
Input contract โ metric: ValueMetric
Defined in app/data/widgets.ts. The API response for this widget maps to exactly this shape.
| Field | Type | Notes |
|---|---|---|
| id | string | Stable id so a page-config slot can reference this metric. |
| name | string | Widget title, e.g. "Pupil Premium Students". |
| family | FamilyKey | Data family ("demographics", "financial"โฆ) โ drives the header identity and colours. |
| lens | LensKey | How to read a high value ("complexity", "success"โฆ) โ drives the ranking colour, interpretation line and trend valence. |
| definition | string | Plain-English definition shown in the header tooltip. |
| value | string | The headline figure, pre-formatted: "39.4%", "ยฃ7.42m", "+0.31". |
| qualifier | string? | Count-of-cohort sub-text beside the value, per client feedback: "99 of 251 students", "6 of 54 staff". The first token renders emphasised. |
| perPupil | string? | Alternative qualifier for money metrics โ renders as "ยฃ6.84k / pupil". Takes precedence over qualifier. |
| trend | "up" | "down" | "flat" | Direction of travel โ the arrow in the header chip. |
| delta | string | Formatted change, e.g. "+1.8pp". Coloured by whether the direction is favourable for the lens. |
| neighbourhoods[].key | string | Cohort key, e.g. "national-all" โ matched against the page's section-level cohort filter. |
| neighbourhoods[].label | string | Cohort label, e.g. "National ยท All schools". |
| neighbourhoods[].percentile | number | This organisation's percentile within that cohort (0โ100) โ drives the ranking panel, distribution marker and data table. |
| neighbourhoods[].dist | number[] | The cohort's distribution as 10 bucket weights (relative heights, any scale) for the histogram. |
Props & events
| Prop | Type | Notes |
|---|---|---|
| metric | ValueMetric | The payload (required) โ see the contract. |
| neighbourhood | string? | Key of the cohort to show, usually from a section-level "Compared with" filter shared by every widget in the row. Defaults to the metric's first neighbourhood. |
| advanced | boolean? | Default true. False = the simplified card: headline only, no ranking panel, no mode toggle. |
| variant | boolean? | Default false. True = hide the lens identity and colour by valence instead (used in the Widget Lab's simplified row). |
| drillable | boolean? | Default false. Marks the widget as having a drill-through; it emits "drill" when triggered. (The footer "More" link was removed per client feedback, so currently nothing triggers it.) |
Wiring it to the API
- Replace the mock payload โ the widget takes one `metric: ValueMetric` prop. In the prototype it's fed from VALUE_METRICS in ~/data/widgets.ts; the API should return one ValueMetric object per card.
- All figures arrive pre-formatted as strings (value "39.4%", delta "+1.8pp", qualifier "99 of 251 students") โ the component renders them verbatim and never parses them. Formatting is the API/mapping layer's job.
- neighbourhoods carries one entry per comparison cohort, each with the organisation's percentile and the cohort's 10-bucket distribution. The three views (ranking, distribution, data) are all derived client-side from this one array โ no further API calls after load.
- The neighbourhood prop selects which cohort is displayed; pages share one section-level filter across a row of these widgets, so the API should return the same cohort keys for every metric on a page.
- LENSES is app configuration, not API data โ the payload only names its family and lens keys.
- The widget emits a single optional "drill" event (only when drillable is set); there is currently no visible trigger for it.

