CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-types--shared

Shared TypeScript type definitions for React Spectrum components and hooks, providing common interfaces for DOM interactions, styling, accessibility, internationalization, and component behavior across the React Spectrum ecosystem

Pending
Overview
Eval results
Files

labelable.mddocs/

Labelable Components

Label positioning, alignment, and form-related properties for consistent labeling patterns across React Spectrum components.

Capabilities

Basic Label Types

Core types for label positioning and alignment.

/**
 * Label position relative to the labeled element
 */
type LabelPosition = "top" | "side";

/**
 * Label alignment within its container  
 */
type Alignment = "start" | "end";

/**
 * How to indicate required fields
 */
type NecessityIndicator = "icon" | "label";

Label Properties

Basic labeling interface for components that need labels.

/**
 * Basic properties for labelable components
 */
interface LabelableProps {
  /** The content to display as the label */
  label?: ReactNode;
}

Spectrum Label Properties

Extended labeling interface with Spectrum-specific positioning and styling options.

/**
 * Spectrum-specific labelable properties with positioning and styling
 */
interface SpectrumLabelableProps extends LabelableProps {
  /**
   * The label's overall position relative to the element it is labeling.
   * @default "top"
   */
  labelPosition?: LabelPosition;

  /**
   * The label's horizontal alignment relative to the element it is labeling.
   * @default "start"
   */
  labelAlign?: Alignment;

  /**
   * Whether the required state should be shown as an icon or text.
   * @default "icon"
   */
  necessityIndicator?: NecessityIndicator;

  /**
   * Whether the label is labeling a required field or group.
   */
  isRequired?: boolean;

  /**
   * A ContextualHelp element to place next to the label.
   */
  contextualHelp?: ReactNode;
}

Usage Examples:

import { 
  LabelableProps, 
  SpectrumLabelableProps, 
  LabelPosition,
  Alignment,
  NecessityIndicator 
} from "@react-types/shared";

// Basic labelable component
interface TextFieldProps extends LabelableProps {
  value?: string;
  onChange?: (value: string) => void;
}

function BasicTextField({ label, value, onChange }: TextFieldProps) {
  return (
    <div>
      {label && <label>{label}</label>}
      <input 
        value={value} 
        onChange={(e) => onChange?.(e.target.value)} 
      />
    </div>
  );
}

// Spectrum labelable component with positioning
interface SpectrumTextFieldProps extends SpectrumLabelableProps {
  value?: string;
  onChange?: (value: string) => void;
  placeholder?: string;
}

function SpectrumTextField({ 
  label,
  labelPosition = "top",
  labelAlign = "start", 
  necessityIndicator = "icon",
  isRequired,
  contextualHelp,
  value, 
  onChange,
  placeholder 
}: SpectrumTextFieldProps) {
  const isLabelSide = labelPosition === "side";
  const alignmentClass = labelAlign === "end" ? "label-end" : "label-start";
  
  return (
    <div className={`field ${isLabelSide ? "field-horizontal" : "field-vertical"}`}>
      {label && (
        <div className={`label-container ${alignmentClass}`}>
          <label>
            {label}
            {isRequired && (
              necessityIndicator === "icon" ? 
                <span className="required-icon">*</span> :
                <span className="required-text"> (required)</span>
            )}
          </label>
          {contextualHelp}
        </div>
      )}
      <input 
        value={value}
        onChange={(e) => onChange?.(e.target.value)}
        placeholder={placeholder}
        required={isRequired}
      />
    </div>
  );
}

// Form group with labels
interface FormGroupProps extends SpectrumLabelableProps {
  children: React.ReactNode;
}

function FormGroup({
  label,
  labelPosition = "top",
  labelAlign = "start",
  isRequired,
  contextualHelp,
  children
}: FormGroupProps) {
  return (
    <fieldset>
      {label && (
        <legend className={`legend-${labelAlign}`}>
          {label}
          {isRequired && <span className="required-icon">*</span>}
          {contextualHelp}
        </legend>
      )}
      {children}
    </fieldset>
  );
}

// Usage examples
function LabelExamples() {
  return (
    <div>
      {/* Basic top-aligned label */}
      <SpectrumTextField
        label="Name"
        labelPosition="top"
        labelAlign="start"
        isRequired
        placeholder="Enter your name"
      />

      {/* Side-aligned label with contextual help */}
      <SpectrumTextField
        label="Email"
        labelPosition="side" 
        labelAlign="end"
        contextualHelp={<button>?</button>}
        placeholder="Enter your email"
      />

      {/* Required field with text indicator */}
      <SpectrumTextField
        label="Password"
        isRequired
        necessityIndicator="label"
        placeholder="Enter password"
      />

      {/* Form group with legend */}
      <FormGroup
        label="Contact Information"
        labelAlign="start"
        isRequired
      >
        <SpectrumTextField label="Phone" />
        <SpectrumTextField label="Address" />
      </FormGroup>
    </div>
  );
}

// Custom hook for label configuration
interface UseLabelConfigOptions {
  defaultPosition?: LabelPosition;
  defaultAlign?: Alignment;
  defaultNecessityIndicator?: NecessityIndicator;
}

function useLabelConfig(options: UseLabelConfigOptions = {}) {
  const {
    defaultPosition = "top",
    defaultAlign = "start", 
    defaultNecessityIndicator = "icon"
  } = options;

  return {
    getLabelProps: (props: Partial<SpectrumLabelableProps>) => ({
      labelPosition: props.labelPosition ?? defaultPosition,
      labelAlign: props.labelAlign ?? defaultAlign,
      necessityIndicator: props.necessityIndicator ?? defaultNecessityIndicator,
      ...props
    })
  };
}

// Using the hook
function ConfigurableForm() {
  const { getLabelProps } = useLabelConfig({
    defaultPosition: "side",
    defaultAlign: "end"
  });

  return (
    <form>
      <SpectrumTextField
        {...getLabelProps({
          label: "Username",
          isRequired: true
        })}
      />
      
      <SpectrumTextField
        {...getLabelProps({
          label: "Bio",
          labelPosition: "top" // Override default
        })}
      />
    </form>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-react-types--shared

docs

collections.md

design-tokens.md

dom-aria.md

drag-drop.md

events.md

index.md

input-handling.md

labelable.md

refs.md

selection.md

styling.md

tile.json