Components
Label
An accessible label, typically paired with Morphos's Field. Purely presentational.
Installation
npx kosmesis add labelpnpm dlx kosmesis add labelyarn dlx kosmesis add labelbunx kosmesis add labelCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { cn } from "@/lib/utils";export interface LabelProps { htmlFor?: string; class?: string; id?: string; children?: Children;}/** * Purely presentational — no Morphos equivalent, same as upstream shadcn/ui. Pairs naturally * with Morphos's `Field` (pass `field.fieldId` as `htmlFor`) but isn't coupled to it, so it also * works as a plain standalone label. */@Component()export class Label extends StatelessComponent<LabelProps> { render() { const { htmlFor, class: cls, id, children } = this.props; return ( <label id={id} htmlFor={htmlFor} class={cn( "flex select-none items-center gap-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 group-data-disabled:pointer-events-none group-data-disabled:opacity-50", cls, )} > {children} </label> ); }}Install the following dependencies:
npm install @praxisjs/csspnpm add @praxisjs/cssyarn add @praxisjs/cssbun add @praxisjs/cssCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";class LabelStyles extends Stylesheet { $root = this.css({ display: "flex", userSelect: "none", alignItems: "center", gap: "0.5rem", fontSize: "0.875rem", fontWeight: 500, lineHeight: 1, }) // Ancestor-prefixed nested rule: applies when a preceding sibling with the peer marker is // `:disabled`, or an ancestor carries `[data-disabled]` — the `@praxisjs/css` equivalent of // Tailwind's `peer-disabled:`/`group-data-disabled:` variants, since CSS nesting allows `&` // anywhere in a compound selector, not just as a prefix. .on("[data-kosmesis-peer]:disabled ~ &", { cursor: "not-allowed", opacity: 0.5 }) .on("[data-disabled] &", { pointerEvents: "none", opacity: 0.5 });}export interface LabelProps { htmlFor?: string; class?: string; id?: string; children?: Children;}/** * Purely presentational — no Morphos equivalent, same as upstream shadcn/ui. Pairs naturally * with Morphos's `Field` (pass `field.fieldId` as `htmlFor`) but isn't coupled to it, so it also * works as a plain standalone label. */@Component()export class Label extends StatelessComponent<LabelProps> { @Styled(LabelStyles) $s!: LabelStyles; render() { const { htmlFor, class: cls, id, children } = this.props; return ( <label id={id} htmlFor={htmlFor} class={cx(this.$s.$root, cls)}> {children} </label> ); }}Examples
Usage
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
<div class="flex flex-col gap-2">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="[email protected]" />
</div>Pairing with Field
import { Field, FieldControl, FieldDescription, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
@Component()
class MyForm extends StatefulComponent {
// A second, separately-tracked instance — the same "instantiate once, pass to every part"
// pattern every Morphos compound component uses. The JSX-mounted <Field> below produces the
// actual container element; `this.field` is what FieldLabel/Control/Description read from.
@State() field = new Field();
render() {
return (
<Field>
<FieldLabel field={this.field}>Email</FieldLabel>
<FieldControl field={this.field}>
<Input id={this.field.fieldId} />
</FieldControl>
<FieldDescription field={this.field}>We'll never share your email.</FieldDescription>
</Field>
);
}
}Label itself doesn't require a Field — pass htmlFor pointing at any input's id for a
plain standalone label.
Props
| Prop | Type | Default |
|---|---|---|
htmlFor | string | — |