The map's scale: a short bar on glass at the bottom right of the map, with the ground distance its length spans written above it, such as "300 m" or "2 km", which shortens and lengthens as the map zooms.
When to use
Use ScaleBar for the map's scale, at the bottom right of the map, so the rider can tell how far apart things are as the map zooms.
Nothing else in Perron does this.
Props
| Name | Type | Default | Description |
|---|---|---|---|
metersPerPixel* | number | — | The ground distance one CSS pixel spans at the map's centre, in metres, as the map gives it at its current zoom and latitude. Required. ScaleBar picks a round distance from it and draws the bar that long. A value that is not a positive finite number shows "—" and says "Unknown". |
scaleLabel | string | The locale's | Overrides "Scale", heard before the distance |
metersUnitLabel | string | The locale's | Overrides "m", the unit after a distance under a kilometre |
kilometersUnitLabel | string | The locale's | Overrides "km", the unit after a distance of a kilometre or more |
unknownLabel | string | The locale's | Overrides "Unknown", heard in place of "—" when metersPerPixel gives no distance |
className | string | — | Joined after pn-ScaleBar on the root |
style | CSSProperties | — | Reaches the root |
ref | Ref<HTMLDivElement> | — | Reaches the root element |
slotProps | { label?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; bar?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; } | — | Props for each part: label, bar. |
metersPerPixel (required)number, default —- The ground distance one CSS pixel spans at the map's centre, in metres, as the map gives it at its current zoom and latitude. Required. ScaleBar picks a round distance from it and draws the bar that long. A value that is not a positive finite number shows "—" and says "Unknown".
scaleLabelstring, default The locale's- Overrides "Scale", heard before the distance
metersUnitLabelstring, default The locale's- Overrides "m", the unit after a distance under a kilometre
kilometersUnitLabelstring, default The locale's- Overrides "km", the unit after a distance of a kilometre or more
unknownLabelstring, default The locale's- Overrides "Unknown", heard in place of "—" when
metersPerPixelgives no distance classNamestring, default —- Joined after
pn-ScaleBaron the root styleCSSProperties, default —- Reaches the root
refRef<HTMLDivElement>, default —- Reaches the root element
slotProps{ label?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; bar?: DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> | undefined; }, default —- Props for each part:
label,bar.
Use it
import { ScaleBar } from '@mylder/perron/patterns'Ask your agent
search_docs({ query: "ScaleBar" })Keyboard and ARIA
ScaleBar has no keys of its own and nothing in it is focusable: a scale is read, not operated. Tab passes it by.
| Key | Does | From |
|---|---|---|
| None | The scale takes no focus and no keys; Tab passes it by | Perron |
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
root | None (generic div) | None | None |
label | None (generic span) | Its text: "Scale" from VisuallyHidden, then "300 m"; or "Scale" and "Unknown" | None |
bar | None: aria-hidden | None; the label says the distance it draws | None |
The root is a plain div, not a landmark, an image or a named region: the scale is one line of text to a screen reader, "Scale 300 m", read in place, and a role="img" with an aria-label would hide the same words in an attribute that expectOwnedStrings and the reader both read less reliably than text.
The label is not a live region: the distance changes with every zoom step and would flood a screen reader, and Accessibility asks that only changes of state be announced, in the screen's own polite live region.
What axe won't catch, from the contract, each with how this component meets it:
- Everything the eye is told, the ear is told, for every shape each prop accepts: the eye gets the distance and, from the bar's shape, that it is a scale; the ear gets "Scale" from
VisuallyHiddenand the same distance from the label's text. With no resolution, the eye gets "—" and the ear "Unknown". No colour carries meaning. - Every landmark and named region has an accessible name: none here; the root is not a landmark.
- Every default label can be overridden:
scaleLabel,metersUnitLabel,kilometersUnitLabelandunknownLabel. - Every shape the type accepts renders, in every variant:
metersPerPixelas a fraction of a metre, as metres and as kilometres, at each of the four round steps, and as0, a negative number,NaNandInfinity, which show "—".ScaleBar.test.tsxruns the rounding over each, and the stories render metres, kilometres, the shortest bar and the unknown. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; nothing animates or collapses. The bar and the "—" are hidden because the words beside them say them, not for animation. - Native semantics first: plain
divandspan, text read in place,aria-hiddenon the drawn bar and the "—", and no ARIA of the pattern's own beyond that. - Focus moves in reading order and returns on close: nothing takes focus or opens; the DOM order, label then bar, is the order on screen.
- Every target is at least
size.target-minsquare: no target; nothing in the scale is pressed. - Loops stop when the system asks for less motion: none here; nothing moves on its own, and the bar's length changes without a transition.
Owned strings
Every word ScaleBar shows or announces is its own: the caller gives a number, never a word. unknown is reused from packages/perron/src/locale/en.ts; the other three are new keys, which the build adds to all four locale files, with the Danish, Swedish and Norwegian below.
The new keys read scale "Scale", metersUnit "m" and kilometersUnit "km", with the units written as the SI symbols in every locale. Content design writes a space before units, "4 min", "45 km/h", so the distance reads "300 m" and "2 km", the symbols every Nordic locale writes the same; the keys follow minutesUnit, Delay's unit after a figure; "Scale" names what the distance measures for a reader who can't see the bar, and is "Målestok", "Skala" and "Målestokk" in the others; symbols, unlike "metres" and "kilometres", need no singular and plural for "1 km" and "2 km".
| Key | English | Override | Seen or heard where |
|---|---|---|---|
scale | "Scale" | scaleLabel | The label part, heard first, through VisuallyHidden; never seen |
metersUnit | "m" | metersUnitLabel | The label part, seen and heard after a figure under 1000, "300 m" |
kilometersUnit | "km" | kilometersUnitLabel | The label part, seen and heard after a figure in kilometres, "2 km" |
unknown | "Unknown" | unknownLabel | The label part when metersPerPixel gives no distance: heard in place of the "—" |
Do and don't
For a caller using the pattern, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | must | Give metersPerPixel for the map's centre, and give it again on every zoom and on every move that changes the latitude much | Give it once and leave it: the scale then claims a distance the map no longer shows | review |
| DD-2 | must | Leave metersPerPixel as NaN until the map has loaded, so the scale shows "—" and says "Unknown" | Pass a guess or 0 before the map is ready: the brand never claims more than the data knows | review |
| DD-3 | should | Place the scale from the screen, at the bottom right beside the map controls, size.panel-gap from the edges at z-index.map-controls | Give it a position, a margin or a z-index through className: the pattern sizes to its content and places nothing | review |
| DD-4 | should | Keep one scale on the map | Put a scale in a panel or a sheet, away from the map it measures | review |
| DD-5 | must | Leave the scale out of the screen's live region; announce changes of state there | Make the label a live region: it changes on every zoom step and would flood a screen reader | review |