Kosmesis
Components

Label

An accessible label, typically paired with Morphos's Field. Purely presentational.

Installation

npx kosmesis add label
pnpm dlx kosmesis add label
yarn dlx kosmesis add label
bunx kosmesis add label

Copy and paste the following code into your project.

label.tsx
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;}// Pairs with Morphos's `Field` (`field.fieldId` as `htmlFor`) but works standalone too.@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/css
pnpm add @praxisjs/css
yarn add @praxisjs/css
bun add @praxisjs/css

Copy and paste the following code into your project.

label.tsx
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,  })    // `&` can appear anywhere in the 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;}// Pairs with Morphos's `Field` (`field.fieldId` as `htmlFor`) but works standalone too.@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

PropTypeDefault
htmlForstring

On this page