Portal Community

Props Contract

interface EditComponentProps {
  control: FormControl;          // Full control config — use control.settings for custom config
  value: any;                    // Current value from form state
  onChange: (value: any) => void; // Must call this when the value changes
  onBlur: () => void;            // Must call this when the input loses focus
  error?: string;                // Validation error — display prominently if present
  mode: FormOperatingMode;       // 'edit' | 'admin' | 'design' | 'preview'
  disabled?: boolean;            // Grey out and prevent interaction
  readOnly?: boolean;            // Display value but don't allow changes
}

Phone Input — Complete Example

import React, { useCallback } from 'react';
import type { EditComponentProps } from '@atlas-forms/types-js';

export const PhoneEditComponent: React.FC<EditComponentProps> = ({
  control,
  value,
  onChange,
  onBlur,
  error,
  disabled,
  readOnly,
}) => {
  const settings = control.settings ?? {};
  const defaultCountry = settings.defaultCountry ?? 'US';
  const showFlag = settings.showFlag ?? true;

  const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    onChange(e.target.value);
  }, [onChange]);

  return (
    <div className="phone-input-wrapper">
      {showFlag && (
        <span className={`flag flag-${defaultCountry.toLowerCase()}`} aria-hidden="true" />
      )}
      <input
        type="tel"
        value={value ?? ''}
        onChange={handleChange}
        onBlur={onBlur}
        disabled={disabled}
        readOnly={readOnly}
        placeholder={control.description ?? 'Enter phone number'}
        aria-label={control.label}
        aria-invalid={!!error}
        aria-describedby={error ? `${control.id}-error` : undefined}
        className={error ? 'has-error' : ''}
      />
      {error && (
        <span
          id={`${control.id}-error`}
          className="field-error"
          role="alert"
        >
          {error}
        </span>
      )}
    </div>
  );
};

Key Rules for EditComponent

Handling Complex Values

For controls that manage structured data (object or array values):

// Address picker — value is an object
interface AddressValue {
  street: string;
  city: string;
  state: string;
  zipCode: string;
}

const AddressEdit: React.FC<EditComponentProps> = ({ value, onChange }) => {
  const address = (value as AddressValue) ?? { street: '', city: '', state: '', zipCode: '' };

  const update = (field: keyof AddressValue, fieldValue: string) => {
    onChange({ ...address, [field]: fieldValue });
  };

  return (
    <div className="address-picker">
      <input value={address.street} onChange={e => update('street', e.target.value)} placeholder="Street" />
      <input value={address.city}   onChange={e => update('city', e.target.value)}   placeholder="City" />
      {/* ... etc */}
    </div>
  );
};