webspark-ui
v1.0.1
Published
Reusable React and Next.js components with Tailwind CSS. Optional React Hook Form and Zod support.
Downloads
3
Maintainers
Readme
webspark-ui
A collection of reusable React and Next.js components built with Tailwind CSS. Works with or without React Hook Form and Zod validation. Perfect for building modern, type-safe forms and UI interfaces.
Installation
npm install webspark-uiRequired Dependencies
The following dependencies are required:
npm install react react-domOptional Dependencies
The following dependencies are optional and only needed if you want to use specific features:
- React Hook Form (
react-hook-form): For form validation withInputFieldcomponent - Zod (
zod): For schema validation (used with React Hook Form)
# Install only if you need form validation
npm install react-hook-form zodComponents
Button
A flexible button component with multiple variants and sizes. Works seamlessly with both React and Next.js applications.
Props
| Prop | Type | Default | Description |
| -------------- | ------------------------------------------------------ | -------------- | ------------------------------------- |
| variant | 'primary' \| 'second' \| 'tertiary' \| 'blackButton' | 'primary' | Button style variant |
| size | 'sm' \| 'md' \| 'lg' | 'md' | Button size |
| fullWidth | boolean | false | Make button full width |
| fullWidthSM | boolean | false | Full width on mobile, auto on desktop |
| type | 'button' \| 'submit' \| 'reset' | 'button' | Button type |
| disabled | boolean | false | Disable the button |
| borderRadius | string | 'rounded-xl' | Custom border radius class |
| leftIcon | ReactNode | - | Icon to display on the left |
| rightIcon | ReactNode | - | Icon to display on the right |
| className | string | '' | Additional CSS classes |
| onClick | function | - | Click handler |
Usage Examples
import { Button } from "webastic-ui";
// Basic button
<Button variant="primary">Click Me</Button>
// Different variants
<Button variant="primary">Primary Button</Button>
<Button variant="second">Secondary Button</Button>
<Button variant="tertiary">Tertiary Button</Button>
<Button variant="blackButton">Black Button</Button>
<Button size="sm">Small Button</Button>
<Button size="md">Medium Button</Button>
<Button size="lg">Large Button</Button>
// Full width button
<Button fullWidth>Full Width Button</Button>
// Button with icons
<Button
leftIcon={<Icon />}
rightIcon={<ArrowIcon />}
>
Button with Icons
</Button>
// Submit button
<Button type="submit" variant="primary">
Submit Form
</Button>
// Disabled button
<Button disabled variant="primary">
Disabled Button
</Button>
// Custom styling
<Button
borderRadius="rounded-full"
className="shadow-lg"
>
Custom Styled Button
</Button>InputField
A comprehensive input field component that works with or without React Hook Form. Supports validation errors and various input types. Compatible with both React and Next.js.
Props
| Prop | Type | Default | Description |
| ------------- | ------------------ | ------------ | ---------------------------------------------------- |
| name | string | required | Field name (used for form registration) |
| label | string | - | Label text for the input |
| placeholder | string | - | Placeholder text |
| type | string | 'text' | Input type (text, email, password, etc.) |
| value | string | - | Controlled input value |
| onChange | function | - | Change handler |
| required | boolean | false | Mark field as required |
| disabled | boolean | false | Disable the input |
| register | function | - | React Hook Form register function (optional) |
| errors | object \| string | - | Validation errors object or error message (optional) |
| area | boolean | false | Render as textarea instead of input |
| className | string | 'relative' | Additional CSS classes |
| widthClass | string | - | Custom width class |
| instruction | string | - | Helper text below input |
| min | any | - | Minimum value (for number inputs) |
| svgprop | ReactNode | - | SVG icon component to display inside input |
| iconsrc | string | - | Image icon source URL |
| iconclass | string | '' | CSS classes for the icon image |
| iconName | string | - | Icon name (for accessibility) |
| areaClass | string | '' | Additional CSS classes for textarea element |
Usage Examples
import { InputField } from "webastic-ui";
import { useForm } from "react-hook-form";
// Basic input field (works without React Hook Form)
<InputField
name="username"
label="Username"
placeholder="Enter your username"
/>
// With controlled value (without React Hook Form)
<InputField
name="email"
label="Email"
placeholder="Enter your email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
// With React Hook Form (optional)
function MyForm() {
const { register, formState: { errors } } = useForm();
return (
<form>
<InputField
name="email"
label="Email Address"
placeholder="Enter your email"
type="email"
register={register("email", {
required: "Email is required",
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: "Invalid email address"
}
})}
errors={errors}
required
/>
<InputField
name="password"
label="Password"
placeholder="Enter your password"
type="password"
register={register("password", {
required: "Password is required",
minLength: {
value: 8,
message: "Password must be at least 8 characters"
}
})}
errors={errors}
required
/>
</form>
);
}
// Textarea
<InputField
name="message"
label="Message"
placeholder="Enter your message"
area={true}
required
/>
// Disabled input
<InputField
name="readonly"
label="Read Only Field"
value="Cannot be edited"
disabled
/>
// With custom instruction
<InputField
name="phone"
label="Phone Number"
placeholder="Enter phone number"
instruction="Include country code (e.g., +1)"
/>
// Number input
<InputField
name="age"
label="Age"
type="number"
min={18}
placeholder="Enter your age"
/>
// With custom width
<InputField
name="search"
label="Search"
placeholder="Search..."
widthClass="w-64"
/>
// With SVG icon
<InputField
name="email"
label="Email"
placeholder="Enter email"
svgprop={<EmailIcon />}
/>
// With image icon
<InputField
name="username"
label="Username"
placeholder="Enter username"
iconsrc="/icons/user.svg"
iconclass="w-5 h-5"
/>
// Textarea with custom area class
<InputField
name="message"
label="Message"
placeholder="Enter your message"
area={true}
areaClass="custom-textarea-class"
required
/>DropDown
A flexible dropdown component that supports both single and multi-select options. Works seamlessly with React Hook Form (using register) or without React Hook Form (using value and onChange). Includes error handling and is compatible with both React and Next.js.
Props
| Prop | Type | Default | Description |
| ------------- | ------------------------------- | -------------------- | ----------------------------------------------------------------------------------------------- |
| label | string | - | Label text for the dropdown |
| options | { value: T; label: string }[] | required | Array of options (T extends string | number) |
| value | T \| T[] | - | Selected value(s) - single value or array for multi-select (required when not using register) |
| onChange | function | - | Change handler function (required when not using register) |
| isMulti | boolean | false | Enable multi-select mode |
| placeholder | string | 'Select an option' | Placeholder text when no option is selected |
| name | string | - | Field name (used for form registration and error handling) |
| required | boolean | false | Mark field as required |
| className | string | 'relative' | Additional CSS classes |
| disabled | boolean | false | Disable the dropdown |
| errors | object \| string | - | Validation errors object or error message (optional) |
| svgprop | ReactNode | - | SVG icon component to display on the left side |
| register | function | - | React Hook Form register function (optional, use with name prop) |
| instruction | string | - | Helper text below dropdown |
Note: You can use the component in two ways:
- With React Hook Form: Provide
registerandnameprops (no need forvalueandonChange) - Without React Hook Form: Provide
valueandonChangeprops
Usage Examples
import { DropDown } from "webastic-ui";
import { useForm } from "react-hook-form";
// ===== WITHOUT REACT HOOK FORM =====
// Basic single-select dropdown
const [selectedValue, setSelectedValue] = useState<string>("");
<DropDown
label="Country"
options={[
{ value: "us", label: "United States" },
{ value: "uk", label: "United Kingdom" },
{ value: "ca", label: "Canada" },
]}
value={selectedValue}
onChange={setSelectedValue}
placeholder="Select a country"
/>
// Multi-select dropdown
const [selectedValues, setSelectedValues] = useState<string[]>([]);
<DropDown
label="Select Languages"
options={[
{ value: "en", label: "English" },
{ value: "es", label: "Spanish" },
{ value: "fr", label: "French" },
{ value: "de", label: "German" },
]}
value={selectedValues}
onChange={setSelectedValues}
isMulti={true}
placeholder="Select languages"
/>
// ===== WITH REACT HOOK FORM =====
// Single-select with React Hook Form
function MyForm() {
const { register, formState: { errors } } = useForm();
return (
<form>
<DropDown
name="country"
label="Country"
options={[
{ value: "us", label: "United States" },
{ value: "uk", label: "United Kingdom" },
{ value: "ca", label: "Canada" },
]}
register={register("country", { required: "Country is required" })}
errors={errors}
required
placeholder="Select a country"
/>
</form>
);
}
// Multi-select with React Hook Form
function MultiSelectForm() {
const { register, formState: { errors } } = useForm();
return (
<form>
<DropDown
name="languages"
label="Select Languages"
options={[
{ value: "en", label: "English" },
{ value: "es", label: "Spanish" },
{ value: "fr", label: "French" },
]}
register={register("languages", { required: "Please select at least one language" })}
errors={errors}
isMulti={true}
required
/>
</form>
);
}
// With error handling (without React Hook Form)
const [errors, setErrors] = useState<Record<string, string>>({});
<DropDown
name="category"
label="Category"
options={[
{ value: "tech", label: "Technology" },
{ value: "design", label: "Design" },
{ value: "marketing", label: "Marketing" },
]}
value={category}
onChange={setCategory}
errors={errors}
required
/>
// With SVG icon
<DropDown
label="Select Option"
options={options}
value={value}
onChange={setValue}
svgprop={<LocationIcon />}
/>
// With instruction text
<DropDown
label="Priority"
options={[
{ value: "low", label: "Low" },
{ value: "medium", label: "Medium" },
{ value: "high", label: "High" },
]}
value={priority}
onChange={setPriority}
instruction="Select the priority level for this task"
/>
// Disabled dropdown
<DropDown
label="Status"
options={options}
value={status}
onChange={setStatus}
disabled
/>
// Number-based options
const [age, setAge] = useState<number | number[]>([]);
<DropDown
label="Age Range"
options={[
{ value: 18, label: "18-25" },
{ value: 26, label: "26-35" },
{ value: 36, label: "36-45" },
]}
value={age}
onChange={setAge}
isMulti={true}
/>CheckBox
A customizable checkbox component with clean styling. Uses the primary color for borders and checkmarks. Compatible with both React and Next.js.
Props
| Prop | Type | Default | Description |
| ---------- | ---------- | ------------ | ---------------------------------------------------- |
| label | string | required | Label text for the checkbox |
| checked | boolean | required | Checked state |
| onChange | function | required | Change handler function (checked: boolean) => void |
| disabled | boolean | false | Disable the checkbox |
Usage Examples
import { CheckBox } from "webastic-ui";
// Basic checkbox
const [isChecked, setIsChecked] = useState(false);
<CheckBox
label="I agree to the terms and conditions"
checked={isChecked}
onChange={setIsChecked}
/>
// Checkbox in a form
function ConsentForm() {
const [agreed, setAgreed] = useState(false);
return (
<form>
<CheckBox
label="I accept the privacy policy"
checked={agreed}
onChange={setAgreed}
/>
<Button
type="submit"
variant="primary"
disabled={!agreed}
>
Continue
</Button>
</form>
);
}
// Disabled checkbox
<CheckBox
label="This option is disabled"
checked={false}
onChange={() => {}}
disabled
/>
// Multiple checkboxes
const [preferences, setPreferences] = useState({
newsletter: false,
notifications: false,
updates: false,
});
<CheckBox
label="Subscribe to newsletter"
checked={preferences.newsletter}
onChange={(checked) =>
setPreferences({ ...preferences, newsletter: checked })
}
/>
<CheckBox
label="Enable notifications"
checked={preferences.notifications}
onChange={(checked) =>
setPreferences({ ...preferences, notifications: checked })
}
/>Complete Form Examples
Example 1: Without React Hook Form (Simple Form with Error Messages)
import { useState } from "react";
import { Button, InputField } from "webastic-ui";
function ContactForm() {
const [formData, setFormData] = useState({
name: "",
email: "",
message: "",
});
const [errors, setErrors] = useState<Record<string, string>>({});
const validateEmail = (email: string) => {
const emailRegex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
return emailRegex.test(email);
};
const handleChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = e.target;
setFormData({
...formData,
[name]: value,
});
// Clear error when user starts typing
if (errors[name]) {
setErrors({
...errors,
[name]: "",
});
}
};
const validateForm = () => {
const newErrors: Record<string, string> = {};
if (!formData.name.trim()) {
newErrors.name = "Name is required";
} else if (formData.name.trim().length < 2) {
newErrors.name = "Name must be at least 2 characters";
}
if (!formData.email.trim()) {
newErrors.email = "Email is required";
} else if (!validateEmail(formData.email)) {
newErrors.email = "Please enter a valid email address";
}
if (!formData.message.trim()) {
newErrors.message = "Message is required";
} else if (formData.message.trim().length < 10) {
newErrors.message = "Message must be at least 10 characters";
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (validateForm()) {
console.log(formData);
// Handle form submission
alert("Form submitted successfully!");
}
};
return (
<form onSubmit={handleSubmit} className="max-w-md mx-auto space-y-4">
<InputField
name="name"
label="Full Name"
placeholder="Enter your name"
value={formData.name}
onChange={handleChange}
errors={errors}
required
/>
<InputField
name="email"
label="Email"
placeholder="Enter your email"
type="email"
value={formData.email}
onChange={handleChange}
errors={errors}
required
/>
<InputField
name="message"
label="Message"
placeholder="Enter your message"
area={true}
value={formData.message}
onChange={handleChange}
errors={errors}
required
/>
<Button type="submit" variant="primary" fullWidth>
Submit
</Button>
</form>
);
}Example 2: With React Hook Form and Zod (Advanced Form)
import { useForm } from "react-hook-form";
import { Button, InputField } from "webastic-ui";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
// Define validation schema
const formSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Invalid email address"),
message: z.string().min(10, "Message must be at least 10 characters"),
});
type FormData = z.infer<typeof formSchema>;
function ContactForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(formSchema),
});
const onSubmit = (data: FormData) => {
console.log(data);
// Handle form submission
};
return (
<form
onSubmit={handleSubmit(onSubmit)}
className="max-w-md mx-auto space-y-4"
>
<InputField
name="name"
label="Full Name"
placeholder="Enter your name"
register={register("name")}
errors={errors}
required
/>
<InputField
name="email"
label="Email"
placeholder="Enter your email"
type="email"
register={register("email")}
errors={errors}
required
/>
<InputField
name="message"
label="Message"
placeholder="Enter your message"
area={true}
register={register("message")}
errors={errors}
required
/>
<Button type="submit" variant="primary" fullWidth>
Submit
</Button>
</form>
);
}Styling
This package uses Tailwind CSS for styling. Make sure you have Tailwind CSS configured in your project:
- Install Tailwind CSS:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p- Configure your
tailwind.config.js:
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
"./node_modules/webastic-ui/**/*.{js,jsx,ts,tsx}",
],
// ... rest of your config
};Important Note
Primary Color Configuration: Some components (like Button, InputField, CheckBox) use the primary Tailwind class (e.g., border-primary, focus:border-primary, focus:ring-primary/20). Make sure you have the primary color defined in your Tailwind configuration. If not defined, you can add it to your tailwind.config.js:
module.exports = {
theme: {
extend: {
colors: {
primary: "#your-primary-color", // e.g., '#3b82f6' for blue
},
},
},
// ... rest of your config
};Alternatively, you can modify the component's className to use standard Tailwind colors like border-blue-500 or any other color class that matches your design system.
React and Next.js Compatibility
This package works seamlessly with both:
- React applications (Create React App, Vite, etc.)
- Next.js applications (Pages Router and App Router)
All components are framework-agnostic and use standard React patterns.
TypeScript Support
This package is written in TypeScript and includes type definitions. All components are fully typed for better developer experience.
License
MIT
