Skip to main content

DInput

A comprehensive input component with support for icons, labels, validation states, and more.

Import

import { DInput } from '@dynamic-framework/ui-react';

TypeScript Interface

type Props = Merge<
  Omit<ComponentPropsWithoutRef<'input'>, 'onChange' | 'value'>,
  NonHTMLInputElementProps
>;

type NonHTMLInputElementProps = BaseProps &
  FamilyIconProps &
  StartIconProps &
  EndIconProps & {
    value?: string;
    label?: string;
    loading?: boolean;
    hint?: string;
    size?: ComponentSize;
    invalid?: boolean;
    valid?: boolean;
    floatingLabel?: boolean;
    inputStart?: ReactNode;
    inputEnd?: ReactNode;
    readonly?: boolean;
    onChange?: (value: string) => void;
    onIconStartClick?: (value?: string) => void;
    onIconEndClick?: (value?: string) => void;
  };

type ComponentSize = 'sm' | 'lg';

type StartIconProps = {
  iconStart?: string;
  iconStartDisabled?: boolean;
  iconStartFamilyClass?: string;
  iconStartFamilyPrefix?: string;
  iconStartAriaLabel?: string;
  iconStartTabIndex?: number;
  iconStartMaterialStyle?: boolean;
};

type EndIconProps = {
  iconEnd?: string;
  iconEndDisabled?: boolean;
  iconEndFamilyClass?: string;
  iconEndFamilyPrefix?: string;
  iconEndAriaLabel?: string;
  iconEndTabIndex?: number;
  iconEndMaterialStyle?: boolean;
};

Props

value
string
The current value of the input.
label
string
Label text for the input field.
placeholder
string
Placeholder text when input is empty.
loading
boolean
default:"false"
If true, displays a loading spinner and disables the input.
hint
string
Helper text displayed below the input.
size
'sm' | 'lg'
Size variant of the input.
invalid
boolean
default:"false"
If true, applies invalid/error styling to the input.
valid
boolean
default:"false"
If true, applies valid/success styling to the input.
floatingLabel
boolean
default:"false"
If true, uses floating label style where label moves up when input has value.
inputStart
ReactNode
Custom content to display at the start of the input (before icons).
inputEnd
ReactNode
Custom content to display at the end of the input (after icons).
readonly
boolean
If true, makes the input read-only.
disabled
boolean
default:"false"
If true, disables the input.
onChange
(value: string) => void
Callback function called when input value changes. Receives the new value as a string.
onIconStartClick
(value?: string) => void
Callback function called when start icon is clicked.
onIconEndClick
(value?: string) => void
Callback function called when end icon is clicked.
iconStart
string
Icon to display at the start of the input.
iconStartFamilyClass
string
CSS class for the start icon font family.
iconStartFamilyPrefix
string
Prefix for the start icon font family.
iconStartMaterialStyle
boolean
Whether to use Material Design style for the start icon.
iconStartDisabled
boolean
If true, disables the start icon button.
iconStartAriaLabel
string
Accessible label for the start icon button.
iconStartTabIndex
number
Tab index for the start icon button.
iconEnd
string
Icon to display at the end of the input.
iconEndFamilyClass
string
CSS class for the end icon font family.
iconEndFamilyPrefix
string
Prefix for the end icon font family.
iconEndMaterialStyle
boolean
Whether to use Material Design style for the end icon.
iconEndDisabled
boolean
If true, disables the end icon button.
iconEndAriaLabel
string
Accessible label for the end icon button.
iconEndTabIndex
number
Tab index for the end icon button.
id
string
Unique identifier for the input element. Auto-generated if not provided.
className
string
Additional CSS classes to apply to the input wrapper.
style
CSSProperties
Inline styles to apply to the input wrapper.

Usage Examples

Basic Input

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('');

  return (
    <DInput
      label="Email"
      placeholder="Enter your email"
      value={value}
      onChange={setValue}
    />
  );
}

With Icons

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('');

  return (
    <DInput
      label="Search"
      placeholder="Search..."
      value={value}
      onChange={setValue}
      iconStart="search"
      iconStartFamilyClass="bi"
    />
  );
}

Validation States

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [email, setEmail] = useState('');
  const isValid = email.includes('@');

  return (
    <div className="d-flex flex-column gap-3">
      <DInput
        label="Valid Input"
        value="[email protected]"
        valid
        hint="Looks good!"
      />
      <DInput
        label="Invalid Input"
        value="invalid-email"
        invalid
        hint="Please enter a valid email."
      />
      <DInput
        label="Email"
        placeholder="[email protected]"
        value={email}
        onChange={setEmail}
        valid={isValid && email.length > 0}
        invalid={!isValid && email.length > 0}
        hint={!isValid && email.length > 0 ? 'Invalid email format' : ''}
      />
    </div>
  );
}

Floating Label

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('');

  return (
    <DInput
      label="Floating Label"
      value={value}
      onChange={setValue}
      floatingLabel
    />
  );
}

With Loading State

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('');
  const [loading, setLoading] = useState(false);

  const handleChange = (newValue: string) => {
    setValue(newValue);
    setLoading(true);
    setTimeout(() => setLoading(false), 1000);
  };

  return (
    <DInput
      label="Search"
      placeholder="Type to search..."
      value={value}
      onChange={handleChange}
      loading={loading}
    />
  );
}

With Addons

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('');

  return (
    <div className="d-flex flex-column gap-3">
      <DInput
        label="Price"
        value={value}
        onChange={setValue}
        inputStart={<span>$</span>}
      />
      <DInput
        label="Website"
        value={value}
        onChange={setValue}
        inputStart={<span>https://</span>}
        inputEnd={<span>.com</span>}
      />
    </div>
  );
}

Size Variants

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('');

  return (
    <div className="d-flex flex-column gap-3">
      <DInput
        label="Small"
        placeholder="Small input"
        size="sm"
        value={value}
        onChange={setValue}
      />
      <DInput
        label="Default"
        placeholder="Default input"
        value={value}
        onChange={setValue}
      />
      <DInput
        label="Large"
        placeholder="Large input"
        size="lg"
        value={value}
        onChange={setValue}
      />
    </div>
  );
}

Clickable Icons

import { DInput } from '@dynamic-framework/ui-react';
import { useState } from 'react';

export default function Example() {
  const [value, setValue] = useState('');

  const handleClear = () => {
    setValue('');
  };

  return (
    <DInput
      label="Search"
      placeholder="Search..."
      value={value}
      onChange={setValue}
      iconStart="search"
      iconStartFamilyClass="bi"
      iconEnd={value ? "x-circle-fill" : undefined}
      iconEndFamilyClass="bi"
      iconEndAriaLabel="Clear search"
      onIconEndClick={handleClear}
    />
  );
}

Build docs developers (and LLMs) love