Enterprise-grade form components for Pulsar framework integrated with formular.dev
A comprehensive, type-safe form component library that seamlessly combines Pulsar framework's reactive architecture with formular.dev form management capabilities.
- 🎯 Type-Safe - Full TypeScript support with generics
- ⚡ Reactive - Built on Pulsar's fine-grained reactivity
- 📋 Declarative - Define forms with simple configuration objects
- ✅ Validation - Integrated with formular.dev validation presets
- 🎨 Styled - Pre-styled with Tailwind CSS
- 🔌 Context-Based - Access form state anywhere in your component tree
- 🚪 Portal System - Flexible command button placement
- ♿ Accessible - WCAG 2.1 compliant components
- 📖 Documented - Comprehensive Storybook stories
# Using pnpm (recommended)
pnpm add @pulsar-framework/formular-ui
# Using npm
npm install @pulsar-framework/formular-ui
# Using yarn
yarn add @pulsar-framework/formular-uiimport{bootstrapApp,AppContextProvider}from'pulsar';import{FormProvider,TextField,Checkbox,useFieldDescriptors,}from'@pulsar-framework/formular-ui';import{createMockFormular}from'@pulsar-framework/formular-ui/helpers';// Define your data interfaceinterfaceLoginData{email: string;password: string;rememberMe: boolean;}// Create your form componentconstLoginForm=()=>{// 1. Define field descriptorsconstfields=useFieldDescriptors<LoginData>({email: {type: 'email',label: 'Email Address',placeholder: 'you@example.com',},password: {type: 'password',label: 'Password',placeholder: '••••••••',},rememberMe: {type: 'checkbox',label: 'Remember me',},});// 2. Create form instanceconstform=createMockFormular('loginForm',fields);// 3. Define handlersconsthandleSave=()=>{constdata=form.getData();console.log('Login data:',data);// Send to API...};consthandleQuit=()=>{form.reset();};// 4. Render with FormProviderreturn(<FormProviderform={form}onSaveCallback={handleSave}onQuitCallback={handleQuit}><divclass="space-y-4"><TextFieldname="email"showLabel={true}showErrors={true}/><TextFieldname="password"showLabel={true}showErrors={true}/><Checkboxname="rememberMe"/></div></FormProvider>);};// Bootstrap your appconstappRoot=bootstrapApp().root('#app').onMount((el)=>console.log('Mounted',el)).build();constapp=(<AppContextProviderroot={appRoot}context={{appName: 'My App'}}><LoginForm/></AppContextProvider>);document.getElementById('app')?.appendChild(app);import{ValidationPresets}from'formular.dev';import{useFieldDescriptors}from'@pulsar-framework/formular-ui';interfaceUserData{username: string;email: string;age: number;}constfields=useFieldDescriptors<UserData>({username: {type: 'text',label: 'Username',validation: ValidationPresets.username(true),// true = requiredplaceholder: 'Enter username',},email: {type: 'email',label: 'Email',validation: ValidationPresets.email(true),// true = requiredplaceholder: 'you@example.com',},age: {type: 'number',label: 'Age',validation: ValidationPresets.minValue(18),// Minimum age validation},});import{// Form ManagementFormProvider,useFormContext,useFieldDescriptors,// Input ComponentsTextField,// Text, email, password, number inputsTextareaInput,// Multi-line textCheckbox,// Single checkboxToggle,// Toggle switchSelectInput,// Dropdown selectRadioGroup,// Radio button group// Portal SystemPortal,PortalSlot,// UtilitiescreateMockFormular,}from'@pulsar-framework/formular-ui';Wraps your form and provides context to all child components.
Props:
form: IFormularBuilder- Formular instance (required)data?: T- Initial form dataonSaveCallback?: () => void- Called when save button clickedonQuitCallback?: () => void- Called when quit button clickedchildren: HTMLElement | (() => HTMLElement)- Form fields
Example:
<FormProviderform={form}onSaveCallback={handleSave}>{/* Your form fields */}</FormProvider>Text input with label, validation, and error display.
Props:
name: string- Field name (required)showLabel?: boolean- Show field label (default: false)showErrors?: boolean- Show validation errors (default: false)showGuides?: boolean- Show helper text (default: false)placeholder?: string- Input placeholder
Example:
<TextFieldname="email"showLabel={true}showErrors={true}showGuides={true}placeholder="Enter your email"/>Checkbox with label and error display.
Props:
name: string- Field name (required)
Example:
<Checkboxname="agreeToTerms"/>Dropdown select with label and validation.
Props:
name: string- Field name (required)showLabel?: boolean- Show field label (default: false)showErrors?: boolean- Show validation errors (default: false)showGuides?: boolean- Show helper text (default: false)
Example:
<SelectInputname="country"showLabel={true}showErrors={true}/>Radio button group with auto-rendered options.
Props:
name: string- Field name (required)showLabel?: boolean- Show field label (default: false)showErrors?: boolean- Show validation errors (default: false)
Example:
<RadioGroupname="gender"showLabel={true}/>Multi-line text input with label and validation.
Props:
name: string- Field name (required)showLabel?: boolean- Show field label (default: false)showErrors?: boolean- Show validation errors (default: false)showGuides?: boolean- Show helper text (default: false)rows?: number- Number of visible rows (default: 4)
Example:
<TextareaInputname="bio"showLabel={true}rows={6}/>Toggle switch with label.
Props:
name: string- Field name (required)
Example:
<Togglename="notifications"/>Use useFormContext() to access form state anywhere in your component tree:
import{useFormContext}from'@pulsar-framework/formular-ui';constCustomComponent=()=>{const{ form, updateField, validateField }=useFormContext();consthandleCustomAction=()=>{constcurrentValue=form.getFieldValue('email');updateField('email','new@email.com');validateField('email');};return<buttononClick={handleCustomAction}>Update Email</button>;};Place form command buttons anywhere in your UI:
import{Portal,PortalSlot}from'@pulsar-framework/formular-ui';constMyApp=()=>{return(<div><header>{/* Portal target in header */}<PortalSlotid="myForm"name="commands"/></header><FormProviderform={form}><TextFieldname="title"/>{/* Buttons render in header, not here! */}<Portalid={form.id}target="commands"><buttononClick={handleSave}>Save</button><buttononClick={handleCancel}>Cancel</button></Portal></FormProvider></div>);};import{IFieldDescriptor}from'formular.dev';constcustomEmailValidator=(value: string): string|null=>{if(!value.endsWith('@company.com')){return'Must be a company email address';}returnnull;};constfields=useFieldDescriptors<UserData>({email: {type: 'email',validation: customEmailValidator,},});Components use Tailwind CSS. You can:
- Use default styles - Components work out-of-the-box with Tailwind
- Customize via Tailwind config - Override colors, spacing, etc.
- Add custom classes - Pass className props to components
// Add Tailwind CDN to your HTML<scriptsrc="https://cdn.tailwindcss.com"></script>// Or install Tailwind in your projectpnpmadd-DtailwindcsspostcssautoprefixerExplore all components interactively:
cd packages/pulsar-formular-ui
pnpm storybookBrowse to http://localhost:6007
Run the demo app:
pnpm devBrowse to http://localhost:3000
See src/demo.tsx for the complete implementation.
@pulsar-framework/formular-ui
├── src/
│ ├── components/
│ │ ├── form-provider/ # FormProvider component
│ │ ├── form-context/ # Form context and hooks
│ │ ├── integrated/ # Full-featured components
│ │ ├── primitives/ # Basic field bindings
│ │ ├── portal/ # Portal system
│ │ └── modal/ # Modal dialogs
│ ├── types/ # TypeScript interfaces
│ ├── utils/ # Utility functions and hooks
│ ├── stories/ # Storybook stories
│ └── demo.tsx # Demo application
Contributions are welcome! Please read our Contributing Guide.
MIT © Tadeo Piana
- Pulsar Framework - Reactive UI framework
- formular.dev - Form management library
- Pulsar UI - Base UI components
- GitHub Repository
See CHANGELOG.md for version history.
Need Help?