Field Lock Mark
Muted decorative lock glyph for read-only field controls.
Field Lock Mark is the one muted lock glyph for a readOnly fill-in field. It is decorative on purpose (aria-hidden): native readonly and Read-Only Hint already announce the state to assistive tech.
Kit hosts compose this; prefer FormItem, Editable Table, or Inline Edit so placement stays one slot per owner. Composition rules: Field Lock Affordance.
When To Use
- Kit hosts composing a custom
readOnlycontrol that FormItem / Editable Table / Inline Edit do not already chrome. - Pair with host-owned reason copy using
fieldLockReasonClass(or the table popover class) — never put the reason on the glyph. - Prefer FormItem (label slot), Editable Table (trailing cell affix), or Inline Edit (trigger slot) instead of mounting this yourself.
- Do not use it for
readPrettyfacts,disabledfields, row/surface locks, or as a security badge.
Features
| Area | Behavior |
|---|---|
| Glyph | Lucide lock, muted, size-3, aria-hidden — never destructive, never a badge |
| Slot | data-slot="field-lock-mark" on the wrapper; hosts pass className for insets |
| Reason | Exported wrap classes for host copy — soft wrap, never truncate |
| AT | No accessible name; Read-Only Hint carries the announcement |
Installing
pnpm dlx shadcn@latest add https://ui.isaacfei.com/r/field-lock-mark.jsonnpx shadcn@latest add https://ui.isaacfei.com/r/field-lock-mark.jsonyarn dlx shadcn@latest add https://ui.isaacfei.com/r/field-lock-mark.jsonbun x shadcn@latest add https://ui.isaacfei.com/r/field-lock-mark.jsonWith a namespace: npx shadcn@latest add @f-ui/field-lock-mark.
registryDependencies: none. Runtime npm: lucide-react.
Usage
import { FieldLockMark } from "@/components/f-ui/internals/field-lock-mark";
<div className="flex items-center gap-1.5">
<span>Warehouse</span>
<FieldLockMark />
</div>Examples
Label Slot
Same placement FormItem uses: the mark sits beside the label, not inside the control. The field stays a box so it still reads as a fill-in field that is locked now.
"use client";
import { FieldLockMark } from "@/components/f-ui/internals/field-lock-mark";
export function FieldLockMarkDemo() {
return (
<div className="max-w-sm space-y-1.5">
<div className="flex items-center gap-1.5">
<span className="text-sm font-medium">Warehouse</span>
<FieldLockMark />
</div>
<input
readOnly
value="East dock"
aria-label="Warehouse"
className="h-8 w-full rounded-lg border border-input bg-transparent px-2.5 text-sm"
/>
</div>
);
}Host Reason Copy
Reason is host-owned text under the control, wrapped with fieldLockReasonClass. The glyph stays silent; the copy explains why.
Posted orders cannot change SKU.
"use client";
import {
FieldLockMark,
fieldLockReasonClass,
} from "@/components/f-ui/internals/field-lock-mark";
export function FieldLockMarkReasonDemo() {
return (
<div className="max-w-sm space-y-1.5">
<div className="flex items-center gap-1.5">
<span className="text-sm font-medium">SKU</span>
<FieldLockMark />
</div>
<input
readOnly
value="WIDGET-104"
aria-label="SKU"
className="h-8 w-full rounded-lg border border-input bg-transparent px-2.5 text-sm"
/>
<p className={fieldLockReasonClass} data-slot="field-lock-reason">
Posted orders cannot change SKU.
</p>
</div>
);
}API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Merged onto the wrapper (table affix padding). Forms pass nothing. |
Constants
| Export | Description |
|---|---|
fieldLockGlyphClass | Glyph classes (text-muted-foreground size-3 shrink-0). |
fieldLockReasonClass | Wrap policy for host reason copy (soft wrap, no truncate). |
fieldLockReasonPopoverClass | Same wrap plus a max-height scrollport for table-cell focus popovers. |
See Also
- Field Lock Affordance — placement, scope, and reason delivery
- Read-Only Hint — screen-reader announcement
- Form (Formily) — FormItem label slot
- Editable Table — trailing cell affix
- Inline Edit — pencil / lock trigger pair