Breakpoint Indicator
A small status badge for the corner of a development build. It reads the viewport,
finds the last breakpoint whose min is at or below the current width, and shows
that name next to a width × height readout. The name rolls when it changes; the
numbers update instantly.
The optional ruler turns the wait for the next breakpoint into a bar: it fills across the gap between the current breakpoint and the next one, with the remaining pixels beside it. At the widest breakpoint it sits full, since there is nowhere left to go.
Visibility is toggled with Ctrl/Cmd + hotkey and remembered in
localStorage. The badge is a development tool, so gate it at the call site —
enabled defaults to true rather than guessing from the build mode, because the
module can be rendered in a docs site, a playground and a preview build that all
report the same environment.
Usage
Resize the window, or press Ctrl/Cmd + B to hide the badge.
<template>
<div class="relative flex h-40 w-full items-center justify-center rounded-lg border border-dashed border-default">
<p class="max-w-xs text-center text-sm text-muted">
Resize the window, or press Ctrl/Cmd + B to hide the badge.
</p>
<MBreakpointIndicator
:fixed="false"
position="bottom-right"
show-ruler
/>
</div>
</template>
fixed is true by default, which pins the badge to position: fixed in the
chosen corner. The example turns it off so the badge travels with the preview box;
in an app, leave it on and drop the component once near the root.
Customize
Customize
breakpoints is sorted by min before use, so the array does not have to be in
order. Anything below the first entry reports as base. The list replaces the
default sm through 2xl set entirely; the component does not read Tailwind's
configuration, so keep the two in step by hand if you change the theme.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
breakpoints | Breakpoint[] | sm, md, lg, xl, 2xl | The widths to compare against. Each entry is { min, name }; min is in
pixels. Sorted internally, and the list is not merged with the defaults. |
enabled | boolean | true | Renders the badge at all. Set it to false — or guard the component with your
own environment check — to keep it out of production. |
visible | boolean | - | Controlled visibility. Leave it out to let the hotkey drive it and remember the
choice in localStorage under a namespaced key. |
fixed | boolean | true | Pins the badge to the viewport. With false it is absolute, so the nearest
positioned ancestor decides where it lands. |
position | 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right' | 'bottom-left' | The corner used by fixed or absolute positioning. |
hotkey | string | 'b' | The character pressed with Ctrl or Cmd to toggle visibility. A single key is
expected; it is compared case-insensitively. |
showSize | boolean | true | Shows the live viewport readout, e.g. 1280×800. |
showRuler | boolean | false | Shows the bar between the active and next breakpoints, plus the pixels left before the next one. |
class | string | - | Extra classes for the badge. |
Events
| Event | Payload | Description |
|---|---|---|
update:visible | (visible: boolean) => void | Fires when the hotkey toggles the badge, whether or not visibility is
controlled. The component also writes the new value to localStorage while it
owns the state. |
Accessibility
- The badge is
role="status"witharia-live="polite"and anaria-labelthat spells out the active breakpoint and both viewport dimensions. A breakpoint change is announced without moving focus. - The ruler and its remaining-pixels label are
aria-hidden. They repeat a secondary, visual detail; the essential state is already in the label. - The badge is not a button. The only interaction is the global hotkey, which is
discoverable from the
titleattribute; a visitor who does not know the shortcut cannot dismiss it by pointer. That is a real limitation of a non-interactive status element, not a hidden control. - The
titlenamesCtrl/Cmd + <hotkey>, and the label stays correct whether the badge is controlled or writing its own visibility. - Under
prefers-reduced-motionthe breakpoint name keeps its hiddeninitialstate but swaps with a zero-duration transition, so the text changes instantly instead of rolling.
Performance
- One
useWindowSizesubscription tracks the viewport; noResizeObserverruns againstdocumentElementand no animation frame is scheduled per resize. - Breakpoint lookup sorts a copy of the list and walks it once per width change. It is a handful of comparisons, not a media-query listener per breakpoint.
- Only the breakpoint label animates, and only on
opacityandtransform. The size readout and the ruler width update as plain text and a percentage. - The badge renders nothing during SSR and until the first client mount, which avoids a hydration mismatch from a viewport width the server cannot know.
- One global
keydownlistener is attached through VueUse and removed on unmount. There is no polling and no timer.
enabled on in a
playground and set it to false — or omit the component — in the production
build. The built-in breakpoints mirror Tailwind's defaults; if you customize the
theme, pass the same min values here.