aravint-ui-form-controls
v1.0.25
Published
To import CSS, use:
Readme
To import CSS, use:
import "@digitus-fci-oa/form-controls/style.css";CustomDatePicker
Single Date
<CustomDatePicker
mode="date"
value={date}
onChangeSingle={setDate}
/>Date & Time
<CustomDatePicker
mode="dateTime"
value={dateTime}
onChangeSingle={setDateTime}
/>Date Range
<CustomDatePicker
mode="range"
fromDate={startDate}
endDate={endDate}
onRangeChange={(start, end) => {
setStartDate(start)
setEndDate(end)
}}
/>Checkbox
Basic Checkbox
import { Checkbox } from "@digitus-fci-oa/form-controls";
import { useState } from "react";
export default function TestCheckbox() {
const [checked, setChecked] = useState(false);
return (
<Checkbox
label="Mandatory Field"
checked={checked}
onChange={setChecked}
/>
);
}Checkbox With Required
<Checkbox
label="Accept Terms & Conditions"
checked={checked}
onChange={setChecked}
required
/>Disabled Checkbox
<Checkbox
label="Disabled Checkbox"
checked={true}
onChange={setChecked}
disabled
/>Checkbox With Test Id
<Checkbox
label="Mandatory Field"
checked={checked}
onChange={setChecked}
dataTestId="mandatory-checkbox"
/>npm install @digitus-fci-oa/form-controls
import { DragDropUpload } from "@digitus-fci-oa/form-controls";
import { Upload } from "lucide-react";
function App() {
const inputRef = useRef<HTMLInputElement>(null);
const [isDragging, setIsDragging] = useState(false);
const [isUploading, setIsUploading] = useState(false);
return (
<DragDropUpload
inputRef={inputRef}
isDragging={isDragging}
isUploading={isUploading}
disabled={false}
multiple={true}
accept=".pdf,.doc,.docx,.png,.jpg"
onFilesChange={(files) => {
console.log(files);
}}
onDrop={(e) => {
e.preventDefault();
setIsDragging(false);
}}
onDragOver={(e) => {
e.preventDefault();
setIsDragging(true);
}}
onDragLeave={() => {
setIsDragging(false);
}}
onClick={() => inputRef.current?.click()}
title="Drag & Drop Files Here"
subtitle="or"
buttonText="Browse"
uploadingText="Uploading files..."
footerText="(File Size Max 10MB)"
icon={<Upload className="w-12 h-12" />}
buttonClassName="
!px-[25px]
!py-[6px]
!bg-[#1570EF]
text-white
hover:bg-[#0047a3]
"
/>
);
}
Props
| Prop | Type | Default | Description |
| ---------------- | ----------------------------- | ------------ | ------------------------------------ |
| label | string | undefined | Checkbox label text |
| checked | boolean | false | Controls checked state |
| onChange | (checked: boolean) => void | � | Triggered when checkbox changes |
| disabled | boolean | false | Disables checkbox |
| id | string | undefined | HTML id for checkbox |
| className | string | "" | Custom wrapper class |
| labelClassName | string | "" | Custom label class |
| required | boolean | false | Shows required asterisk |
| dataTestId | string | undefined | Test id for automation/testing |
| onFilesChange | (files: FileList \| null) => void | undefined | Callback triggered when files are
| accept | string | "*" | Allowed file types |
| multiple | boolean | true | Allows multiple file selection |
| disabled | boolean | false | Disables uploader interactions |
| isUploading | boolean | false | Shows uploading state |
| title | string | "Drag & Drop Files Here" | Main upload area itle |
| subtitle | string | "or" | Subtitle text below title |
| buttonText |string | "Browse" | Browse button text |
| uploadingText | string | "Uploading files..." | Uploading message text |
| footerText | string | "(File Size Max 10MB)" | Footer/helper text |
| icon | React.ReactNode | undefined | Custom upload icon |
| containerClassName | string | "" | Custom wrapper/container class |
| dropZoneClassName | string | "" | Custom dropzone class |
| buttonClassName | string | "" | Custom browse button class |
| inputId | string | "file-upload" | Custom input element id |
MultiSelect Component
A lightweight, accessible multi-select dropdown built with React and Tailwind CSS.
Usage
import { MultiSelect } from "./components/MultiSelect";
const options = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
];
function App() {
const [selected, setSelected] = React.useState<string[]>([]);
return (
<MultiSelect
options={options}
value={selected}
onChange={setSelected}
placeholder="Select fruits..."
/>
);
}interface TooltipProps {
value: string;
icon?: React.ReactNode;
}
import Tooltip from "@digitus-fci-oa/form-controls";
<Tooltip
value="View Questionnaire"
icon={
<Eye
size={16}
className="cursor-pointer text-blue-600"
/>
}
/>
Props
| Prop | Type | Required | Default | Description |
|---------------|-------------------------------|----------|----------------|------------------------------------------|
| options | Option[] | ✅ | — | List of options to display |
| value | string[] | ✅ | — | Currently selected values |
| onChange | (value: string[]) => void | ✅ | — | Callback when selection changes |
| placeholder | string | ❌ | "Select..." | Text shown when nothing is selected |
| error | string | ❌ | — | Error message shown below the dropdown |
value="View Questionnaire"| string | | text
Option Type
interface Option {
label: string; // Display text
value: string; // Underlying value
}Features
- Multi-selection with toggle behavior (click to select/deselect)
- Selected labels shown as comma-separated text in the trigger button
- Dropdown opens/closes on button click
- Red border and error message on validation failure via
errorprop - Scrollable list capped at
max-h-60 - Checkmark indicator on selected items
Error State
Pass an error string to show validation feedback:
<MultiSelect
options={options}
value={selected}
onChange={setSelected}
error="Please select at least one option."
/>Close on Outside Click
The dropdown does not close automatically on outside click. Add this to your component if needed:
---
## Dependencies
| Package | Purpose |
|-----------------|--------------------------------|
| `lucide-react` | Icons (`ChevronDown`, `Check`) |
| `tailwindcss` | Utility-based styling |
| `clsx` / `tailwind-merge` | `cn()` utility for class merging |
---
## File Structure
src/ ├── components/ │ └── MultiSelect.tsx ← Component file └── lib/ └── utils.ts ← cn() utility
# Textarea Component
A resizable textarea input built with React and Tailwind CSS, with built-in error state support.
---
## Usage
```tsx
import { Textarea } from "./components/Textarea";
function App() {
const [value, setValue] = React.useState("");
return (
<Textarea
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Enter your text here..."
/>
);
}Props
| Prop | Type | Required | Default | Description |
|-------------|-----------|----------|------------------------------|----------------------------------------------------------|
| error | string | ❌ | — | Error message displayed below the textarea |
| className | string | ❌ | — | Additional Tailwind classes to merge |
| ref | Ref | ❌ | — | Forwarded ref to the underlying <textarea> element |
| ...rest | React.TextareaHTMLAttributes | ❌ | — | All standard HTML textarea attributes (onChange, disabled, rows, etc.) |
Extends all native
React.TextareaHTMLAttributes<HTMLTextAreaElement>props.
Features
- Forwarded ref support via
React.forwardRef - Built-in error state with red border and error message
- Fixed height of
4.5remwithresize-noneby default - Custom
classNamesupport withcn()merge utility - Default placeholder text
Error State
Pass an error string to highlight the field and show a message:
<Textarea
value={value}
onChange={(e) => setValue(e.target.value)}
error="This field is required."
/>With React Hook Form
import { useForm } from "react-hook-form";
import { Textarea } from "./components/Textarea";
function Form() {
const { register, formState: { errors } } = useForm();
return (
<Textarea
{...register("description", { required: "Description is required" })}
error={errors.description?.message}
/>
);
}Customizing Height
Override the default height using className:
<Textarea className="h-32" /> {/* taller */}
<Textarea className="h-20" /> {/* shorter */}Dependencies
| Package | Purpose |
|---------------------------|----------------------------------|
| react | forwardRef, TextareaHTMLAttributes |
| tailwindcss | Utility-based styling |
| clsx / tailwind-merge | cn() utility for class merging |
File Structure
src/
├── components/
│ └── Textarea.tsx ← Component file
└── lib/
└── utils.ts ← cn() utilityToggle Switch
Usage
import { ToggleSwitch } from "@digitus-fci-oa/form-controls"; import { useState } from "react";
export default function TestToggleSwitch() { const [enabled, setEnabled] = useState(false);
return ( <ToggleSwitch checked={enabled} onChange={setEnabled} label={enabled ? "Yes" : "No"} /> ); }
Props
| Prop | Type | Default | Description |
| ---------- | ---------------------------- | ----------- | ----------------------------------- |
| checked | boolean | false | Controls toggle state |
| onChange | (checked: boolean) => void | — | Triggered when toggle state changes |
| disabled | boolean | false | Disables toggle interaction |
| label | string | undefined | Optional label beside toggle |
RadioButton
import { Radio } from "@digitus-fci-oa/form-controls"; import { useState } from "react";
export default function TestRadio() { const [selected, setSelected] = useState("yes");
return (
<Radio
label="Yes"
name="approval"
value="yes"
checked={selected === "yes"}
onChange={setSelected}
/>
<Radio
label="No"
name="approval"
value="no"
checked={selected === "no"}
onChange={setSelected}
/>
</div>); }
Props
| Prop | Type | Default | Description |
| ---------- | ------------------------- | ----------- | ------------------------------------- |
| label | string | undefined | Radio label text |
| name | string | — | Shared group name for radio selection |
| value | string | — | Value of radio option |
| checked | boolean | false | Controls selected state |
| onChange | (value: string) => void | — | Triggered when option changes |
| disabled | boolean | false | Disables radio interaction |
-----------------------------------------------Input field Latest-------------------------------
Input Component
A flexible, fully controlled input component built with React and inline styles — no Tailwind dependency in the consuming app.
Installation
npm i @hari_digitus/sms-ui-libraryImport
import { Input } from "@hari_digitus/sms-ui-library";Props
| Prop | Type | Default | Description |
|---|---|---|---|
| inputSize | "sm" \| "md" \| "lg" | "md" | Controls height and font size |
| error | string | undefined | Shows red border and red error message below input |
| hint | string | undefined | Shows gray hint text below input (only shown when no error) |
| label | string | undefined | Label rendered above the input |
| required | boolean | false | Appends red * to the label |
| leadingIcon | React.ReactNode | undefined | Icon rendered on the left side of the input |
| trailingIcon | React.ReactNode | undefined | Icon rendered on the right side of the input |
| regex | RegExp | undefined | Blocks characters that don't match the pattern while typing |
| onRegexFail | (value: string) => void | undefined | Called when the typed value fails the regex test |
| placeholder | string | "Enter text.." | Placeholder text (font-weight 400, color #6F778E) |
| type | string | "text" | HTML input type: "text", "password", "email", "number", "tel" etc. |
| disabled | boolean | false | Disables the input — gray background, not-allowed cursor, no caret |
| readOnly | boolean | false | Makes input read-only — gray background, not-allowed cursor, no caret |
| value | string | undefined | Controlled value |
| defaultValue | string | undefined | Uncontrolled default value |
| onChange | (e: ChangeEvent<HTMLInputElement>) => void | undefined | Change handler — called only when value passes regex (if set) |
| onBlur | (e: FocusEvent<HTMLInputElement>) => void | undefined | Blur handler |
| onFocus | (e: FocusEvent<HTMLInputElement>) => void | undefined | Focus handler |
| onKeyDown | (e: KeyboardEvent<HTMLInputElement>) => void | undefined | Key down handler |
| onKeyUp | (e: KeyboardEvent<HTMLInputElement>) => void | undefined | Key up handler |
| maxLength | number | undefined | Maximum number of characters allowed |
| minLength | number | undefined | Minimum number of characters required |
| min | number | undefined | Minimum value (for type="number") |
| max | number | undefined | Maximum value (for type="number") |
| step | number | undefined | Step value (for type="number") |
| pattern | string | undefined | HTML pattern attribute for form validation |
| autoComplete | string | undefined | Browser autocomplete hint e.g. "off", "email" |
| autoFocus | boolean | false | Autofocus on mount |
| spellCheck | boolean | undefined | Enable or disable spellcheck |
| id | string | undefined | Custom id — auto-generated from label if not provided |
| name | string | undefined | Input name for form submission |
| tabIndex | number | undefined | Tab order |
| style | React.CSSProperties | undefined | Override any inline style (border, height, background etc.) |
| className | string | undefined | Additional CSS class names |
Size Reference
| inputSize | Height | Font Size |
|---|---|---|
| sm | 34px | 12px |
| md | 40px | 14px |
| lg | 48px | 16px |
Examples
Basic
<Input placeholder="Enter text" />With Error
<Input
placeholder="Enter department name"
error="This field is required"
/>With Hint
<Input
placeholder="Enter email"
hint="We'll never share your email"
/>With Label
<Input
label="Department Name"
required
placeholder="Enter department name"
/>With Label + Error
<Input
label="Department Name"
required
placeholder="Enter department name"
error="This field is required"
/>Sizes
<Input inputSize="sm" placeholder="Small input" />
<Input inputSize="md" placeholder="Medium input" />
<Input inputSize="lg" placeholder="Large input" />Disabled
<Input placeholder="Disabled input" disabled />Read Only
<Input value="Read only value" readOnly />Password
<Input type="password" placeholder="Enter password" />With Leading Icon
import { SearchIcon } from "lucide-react";
<Input
placeholder="Search..."
leadingIcon={<SearchIcon size={16} />}
/>With Trailing Icon
import { EyeIcon } from "lucide-react";
<Input
type="password"
placeholder="Enter password"
trailingIcon={<EyeIcon size={16} />}
/>Numbers Only (Regex)
const [value, setValue] = useState("");
const [error, setError] = useState("");
<Input
placeholder="Enter number"
value={value}
regex={/^\d+$/}
onRegexFail={() => setError("Only numbers allowed")}
onChange={(e) => {
setValue(e.target.value);
setError("");
}}
error={error}
/>Letters Only (Regex)
<Input
placeholder="Enter name"
regex={/^[a-zA-Z\s]+$/}
onRegexFail={() => setError("Only letters allowed")}
/>Email with Regex
const [value, setValue] = useState("");
const [error, setError] = useState("");
const isValidEmail = (val: string) =>
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val);
<Input
placeholder="Enter email"
value={value}
regex={/^[a-zA-Z0-9._%+\-@]*$/}
onRegexFail={() => setError("Invalid characters")}
onChange={(e) => {
setValue(e.target.value);
setError("");
}}
onBlur={() => {
if (value && !isValidEmail(value)) {
setError("Please enter a valid email");
}
}}
error={error}
/>Phone Number (Max 10 digits)
<Input
placeholder="Enter phone number"
regex={/^\d{0,10}$/}
onRegexFail={() => setError("Maximum 10 digits allowed")}
type="tel"
/>Style Override
{/* Custom border color */}
<Input
placeholder="Enter text"
style={{ border: "1px solid #F79009" }}
/>
{/* Custom height */}
<Input
placeholder="Enter text"
style={{ height: "56px" }}
/>
{/* Custom background */}
<Input
placeholder="Enter text"
style={{ backgroundColor: "#F0F4FF" }}
/>Max Length
<Input
placeholder="Enter text"
maxLength={50}
/>Controlled Input
const [value, setValue] = useState("");
<Input
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder="Controlled input"
/>Styling Notes
- All styles are applied via inline
style— no Tailwind dependency in the consuming app styleprop is spread last so consumer overrides always win- Typed text is
font-weight: 500, placeholder isfont-weight: 400 readOnlyanddisabledboth apply#F3F3F3background,not-allowedcursor, and hidden caret- Error border
#FDA29Band error text#F04438are applied automatically whenerrorprop is passed
