@surstromming/label
| Install | |
|---|---|
npm install @surstromming/label |
|
| Latest Version: | 0.1.1 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Oct 17, 2026 |
| Links: | GitHub · npm |
@surstromming/label
Caption for a form control. A native <label> — clicking it focuses the
control it points at.
Dependency graph
graph LR
label["@surstromming/label"]
design["@surstromming/design"]
label --> design
Usage
<template>
<Label for="email">Email</Label>
<Input id="email" v-model="email" type="email" />
</template>
<script setup lang="ts">
import { Label } from '@surstromming/label'
import { Input } from '@surstromming/input'
</script>
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
disabled |
boolean |
false |
Dims the label and blocks its clicks — mirror the control's own disabled |
for is not a prop: it's a native attribute and
falls through. shadcn dims its label from the input's state
with Tailwind's peer-disabled:, which needs a sibling selector we don't
have — so the disabled look is an explicit prop instead of hidden coupling.
Slots
| Slot | Description |
|---|---|
default |
The caption. Icons and a required marker fit inline (flex row). |
Fallthrough
The root is the <label> — for, class, @click, data-* land on it
(inheritAttrs: true).
Anatomy
label.root // flex row, gap, text-sm, medium, non-selectable
└─ .isDisabled // 50% opacity, no pointer events
Tokens
Inherits its color (foreground via the reset) — no color of its own, so it
reads correctly inside any surface. font-size: 0.875rem, font-weight: 500,
gap: spacing(2), user-select: none (a double-click on a caption should
focus the field, not select the word). line-height: 1.25 with
margin-block: -0.125em: a caption that wraps has room between its lines,
and one of a single line of text takes exactly the room line-height: 1
gave it, so a form keeps its rhythm. A line beside something taller than its
text, an icon or a checkbox, takes up to 3.5 px less than it did.
Accessibility
formust match the control'sid. That's what makes the label clickable and what a screen reader announces with the field — this is the whole point of the component.- Wrapping the control instead of using
foralso works natively, but the explicitfor/idpair survives refactors better. disabledis presentational only — it dims the caption; the control still needs its owndisabled.
Recipes
<!-- Required marker -->
<Label for="name">Name <span aria-hidden="true">*</span></Label>
<Input id="name" v-model="name" required />
<!-- Disabled field: both the control and its caption -->
<Label for="plan" disabled>Plan</Label>
<Input id="plan" v-model="plan" disabled />
<!-- Checkbox: caption sits beside the box -->
<Label for="terms"><input id="terms" v-model="agreed" type="checkbox" /> Accept terms</Label>
Related Packages
Modal dialog, with an alert-dialog mode and sheets on the screen's edges.
Everything related to design system, including colors, typography, and spacing.
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.1.1 | ^3.4.0 | MIT | |
| 0.1.0 | ^3.4.0 | MIT |