Docs/uiv1.0.0-rc.1

Input Component

Overview

Input is an accessible, theme-aware, validation-integrated form input component. It extends BaseComponent<InputProps> and is decorated with @Component({ selector: 'udiot-input' }). It injects both ThemeService and ValidationService via @InjectProperty(). When validationRules are provided, the component validates value on initialisation and renders an error message when validation fails. An optional AIStyler generates CSS at render time.

Key Concepts

  • Renders an <input> inside a .input-group wrapper with an associated <label> and optional error message.
  • Full ARIA support: aria-invalid, aria-describedby (pointing to the error element), required.
  • Validates against ValidationRule[] using the injected ValidationService.
  • Integrates with ThemeService for automatic light/dark styling.
  • Error display: either the explicit error prop or the result from ValidationService is shown as .input-error.
  • createInput(props) factory for convenience instantiation.

API Reference

InputProps

interface InputProps {
  type?: 'text' | 'email' | 'password' | 'number'; // Input type (default: 'text')
  placeholder?: string;                              // Placeholder text
  value?: string;                                    // Initial value
  disabled?: boolean;                                // Disable the input (default: false)
  required?: boolean;                                // Mark as required (default: false)
  label?: string;                                    // Label text; rendered as <label> above input
  error?: string;                                    // Explicit error message to display
  validationRules?: ValidationRule[];               // Rules applied via ValidationService on init
  onChange?: (value: string) => void;                // Change handler (client-side only)
  aiStyler?: AIStyler;                              // AI styling bridge; omit for built-in styles
}

ValidationRule is defined in src/services/api/ — refer to the validation service documentation for the full rule shape.

Input

@Component({ selector: 'udiot-input' })
class Input extends BaseComponent<InputProps> {
  constructor(props: InputProps);
  render(): string;  // Returns the full HTML string including <style>
}

Factory

function createInput(props: InputProps): Input;

Basic Usage

import { createInput } from '@tagna/udiot';

const nameInput = createInput({
  type: 'text',
  label: 'Full Name',
  placeholder: 'Jane Smith',
  required: true,
  value: '',
});

console.log(nameInput.render());
// <style>.input-group { ... }</style>
// <div class="input-group">
//   <label class="input-label" for="input-xyz">Full Name *</label>
//   <input id="input-xyz" class="input-field" type="text" placeholder="Jane Smith"
//          value="" required aria-invalid="false" aria-describedby="" />
// </div>

Common Patterns

Email input with error

const emailInput = createInput({
  type: 'email',
  label: 'Email Address',
  placeholder: 'you@example.com',
  required: true,
  value: 'not-an-email',
  error: 'Please enter a valid email address.',
});
// Renders with .has-error class on input and a visible .input-error div

Password input

const passwordInput = createInput({
  type: 'password',
  label: 'Password',
  placeholder: 'At least 8 characters',
  required: true,
});

Disabled input

const readOnlyField = createInput({
  type: 'text',
  label: 'Username',
  value: 'johndoe',
  disabled: true,
});

Validation rule shape (requires application integration)

import { createInput } from '@tagna/udiot';
import type { InputProps } from '@tagna/udiot';

const minLengthRule: NonNullable<InputProps['validationRules']>[number] = {
  type: 'minLength',
  value: 8,
  message: 'Password must be at least 8 characters',
};

const passwordInput = createInput({
  type: 'password',
  label: 'New Password',
  required: true,
  value: 'abc',   // Too short — ValidationService will set validationError
  validationRules: [minLengthRule],
});
// Only if the internal validation service is wired, this can render: "Password must be at least 8 characters"

Composing a login form in SSR

import { createInput, createButton } from '@tagna/udiot';

export default {
  render(): string {
    const email    = createInput({ type: 'email',    label: 'Email',    required: true });
    const password = createInput({ type: 'password', label: 'Password', required: true });
    const submit   = createButton({ children: 'Sign In', variant: 'primary' });

    return `
      <form method="POST" action="/login">
        ${email.render()}
        ${password.render()}
        ${submit.render()}
      </form>
    `;
  },
};

Integration Notes

  • Each Input instance generates a unique id (input-{random}) for the <label for> / <input id> association so label clicks correctly focus the input — even when multiple inputs are rendered on the same page.
  • aria-invalid is set to "true" when error or validationError is non-empty, satisfying WCAG 1.3.1 (Info and Relationships). The error element ID is used as aria-describedby so screen readers announce the error message when the field is focused.
  • ValidationService.validate(value, rules) is called synchronously inside validateValue(). If the service is not injected (manual instantiation outside DI), validation is skipped and the component renders without an error even if validationRules is provided.
  • required: true adds both the HTML required attribute and appends * to the label text. Browser-native validation is therefore active in addition to ValidationService validation.
  • The onChange prop is not wired into the rendered HTML; it is for client-side usage only. Use data-event="change" / data-handler="myHandler" for SSR-compatible event delegation.

Pitfalls

  • label is optional. When omitted, no <label> is rendered. Screen-reader users will lose the label association — always provide a label for accessible forms.
  • error takes precedence over validationError only in display priority: both are evaluated, but only one is shown. If you pass an explicit error prop, the ValidationService result is computed but not shown.
  • The generated id is random (Math.random()). In SSR, the same component rendered on server and client will get different IDs, potentially causing a hydration mismatch warning in frameworks that verify DOM consistency. Pass a stable id via a custom attribute or manage IDs in the page component if you need consistency.
  • validationRules are only evaluated on construction (inside onInit()). If value changes after construction, re-validation does not happen automatically — create a new Input instance or call validateValue() manually.
From the canonical UDIOT public documentation.Try it in the playground ↗