npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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 error prop
  • 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.5rem with resize-none by default
  • Custom className support with cn() 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() utility

Toggle 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-library

Import

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
  • style prop is spread last so consumer overrides always win
  • Typed text is font-weight: 500, placeholder is font-weight: 400
  • readOnly and disabled both apply #F3F3F3 background, not-allowed cursor, and hidden caret
  • Error border #FDA29B and error text #F04438 are applied automatically when error prop is passed