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
The current value of the input.
Label text for the input field.
Placeholder text when input is empty.
If true, displays a loading spinner and disables the input.
Helper text displayed below the input.
Size variant of the input.
If true, applies invalid/error styling to the input.
If true, applies valid/success styling to the input.
If true, uses floating label style where label moves up when input has value.
Custom content to display at the start of the input (before icons).
Custom content to display at the end of the input (after icons).
If true, makes the input read-only.
If true, disables the input.
Callback function called when input value changes. Receives the new value as a string.
Callback function called when start icon is clicked.
Callback function called when end icon is clicked.
Icon to display at the start of the input.
CSS class for the start icon font family.
Prefix for the start icon font family.
Whether to use Material Design style for the start icon.
If true, disables the start icon button.
Accessible label for the start icon button.
Tab index for the start icon button.
Icon to display at the end of the input.
CSS class for the end icon font family.
Prefix for the end icon font family.
Whether to use Material Design style for the end icon.
If true, disables the end icon button.
Accessible label for the end icon button.
Tab index for the end icon button.
Unique identifier for the input element. Auto-generated if not provided.
Additional CSS classes to apply to the input wrapper.
Inline styles to apply to the input wrapper.
Usage Examples
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}
/>
);
}