Skip to content

Input ​

A flexible text input component with labels, hints, validation states, icons, and full Pulse Framework reactivity support.

Import ​

tsx
import { Input, Pulse } from '@odyssee-software/components';

Basic Usage ​

Code Éditable
Résultat

Input Types ​

The Input component supports various HTML5 input types.

Code Éditable
Résultat

With Label ​

Code Éditable
Résultat

With Hint ​

Code Éditable
Résultat

Validation States ​

Code Éditable
Résultat

With Icon ​

Code Éditable
Résultat

Sizes ​

Three size options are available: sm, md, and lg.

Code Éditable
Résultat

Reactive Input with Signals ​

Bind input values to Pulse signals for full reactivity.

tsx
const email = Pulse.signal('');

const reactiveInput = (
  <Input 
    label="Email"
    type="email"
    value={email}
    onChange={(val) => email(val)}
    placeholder="you@example.com"
  />
);

// Use the value elsewhere
Pulse.effect(() => {
  console.log('Email changed:', email());
});

Required Fields ​

Code Éditable
Résultat

Disabled State ​

Code Éditable
Résultat

Readonly State ​

Code Éditable
Résultat

Reactive Validation ​

Validate input in real-time with computed values.

tsx
const email = Pulse.signal('');

const isValidEmail = Pulse.computed(() => {
  const value = email();
  return value.includes('@') && value.includes('.');
});

const errorMessage = Pulse.computed(() => {
  const value = email();
  if (value.length === 0) return '';
  return isValidEmail() ? '' : 'Please enter a valid email address';
});

const validatedInput = (
  <Input 
    label="Email Address"
    type="email"
    value={email}
    onChange={(val) => email(val)}
    error={errorMessage}
    placeholder="you@example.com"
  />
);

Props ​

PropTypeDefaultDescription
type"text" | "email" | "password" | "number" | "tel" | "url" | "search""text"Input type
valuestring | Signal<string>-Input value (reactive or static)
placeholderstring""Placeholder text
labelstring-Label text
hintstring-Hint text below input
errorstring | Signal<string>-Error message
successstring | Signal<string>-Success message
size"sm" | "md" | "lg""md"Input size
iconstring-Icon to display
iconPosition"left" | "right""left"Icon position
disabledbooleanfalseDisable input
readonlybooleanfalseMake readonly
requiredbooleanfalseMark as required
onChange(value: string) => void-Change callback
classNamestring-Additional CSS classes

Accessibility ​

The Input component follows accessibility best practices:

  • ✅ Proper <label> association with for attribute
  • ✅ aria-describedby for hint and error messages
  • ✅ aria-invalid when in error state
  • ✅ required attribute for required fields
  • ✅ Keyboard navigation support
  • ✅ Screen reader friendly

ARIA Attributes ​

tsx
const accessibleInput = (
  <Input
    label="Email"
    type="email"
    aria-label="Email address"
    aria-describedby="email-hint"
  />
);

Best Practices ​

✅ Do ​

  • Use appropriate input types for better UX and validation
  • Provide clear labels for all inputs
  • Use hints to guide users
  • Show validation errors inline
  • Use signals for reactive forms
tsx
// Good: Clear label, type, validation
const goodInput = (
  <Input 
    type="email"
    label="Email Address"
    hint="We'll never share your email"
    required={true}
  />
);

❌ Don't ​

  • Don't omit labels (except search inputs)
  • Don't use vague placeholder text
  • Don't validate before user interaction
  • Don't forget to handle onChange
tsx
// Bad: No label, vague placeholder
const badInput = (
  <Input placeholder="Enter something" />
);

// Better: Clear label and placeholder
const betterInput = (
  <Input 
    label="Full Name"
    placeholder="John Doe"
  />
);

Common Patterns ​

Pattern 1: Search Input ​

tsx
const searchQuery = Pulse.signal('');

const searchInput = (
  <Input
    type="search"
    icon="🔍"
    iconPosition="left"
    placeholder="Search articles..."
    value={searchQuery}
    onChange={(val) => searchQuery(val)}
  />
);

Pattern 2: Password Strength Indicator ​

tsx
const password = Pulse.signal('');

const passwordStrength = Pulse.computed(() => {
  const val = password();
  if (val.length < 6) return 'weak';
  if (val.length < 10) return 'medium';
  return 'strong';
});

const strengthColor = Pulse.computed(() => {
  const strength = passwordStrength();
  return strength === 'weak' ? 'danger' : 
         strength === 'medium' ? 'warning' : 'success';
});

const passwordInput = (
  <div>
    <Input
      type="password"
      label="Password"
      value={password}
      onChange={(val) => password(val)}
      hint={`Strength: ${passwordStrength()}`}
    />
  </div>
);
tsx
const searchQuery = Pulse.signal('');
let debounceTimer: number;

const debouncedSearch = (value: string) => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    console.log('Searching for:', value);
    // Perform search
  }, 300);
};

const debouncedInput = (
  <Input
    type="search"
    placeholder="Search..."
    value={searchQuery}
    onChange={(val) => {
      searchQuery(val);
      debouncedSearch(val);
    }}
  />
);

Styling & Theming ​

All input styles use Tailwind CSS classes and support dark mode automatically.

Custom Styling ​

tsx
const customInput = (
  <Input 
    className="border-2 border-blue-500 focus:ring-4"
    placeholder="Custom styled input"
  />
);

TypeScript ​

Full TypeScript support with complete type definitions:

tsx
import type { InputProps } from '@odyssee-software/components';

const props: InputProps = {
  type: 'email',
  label: 'Email',
  required: true,
  onChange: (value: string) => {
    console.log('Value changed:', value);
  }
};

const input = <Input {...props} />;

Version: 1.0.0
Last Updated: January 2025

Released under the MIT License.