Skip to content



Form-Builder (aka afform) is a core extension currently in active development. It is intended to become the main building tool for CiviCRM forms and layouts going forwards.


Afforms can be embedded on any CiviCRM page as Angular directives; they also can be configured to automatically appear on the dashboard or contact summary screen. Afforms can be embedded into other Afforms simply by including the directive for one Afform in the markup of another; Angular dependencies will be resolved automatically.

Embedding in Smarty Templates

Adding Afforms to traditional Smarty-based pages or forms can be a transitional step away from legacy screens

PHP Code


$this->assign('myAfformVars', $optionalVars);

Note - to figure out what to put in 'name' look at the name in the FormBuilder listing for your form. In the above example the 'name' would be the entire 'afformMyForm' (there isn't a magic prefix).

Template Code

<crm-angular-js modules="afformMyForm">
  <form id="bootstrap-theme">
    <afform-my-form options='{$myAfformVars|@json_encode}'></afform-my-form>

Afform Types

  • form: A form which submits through the Afform::submit api, editable in the form-builder GUI.
  • block: A snippet meant to be incorporated into a larger form.
  • system (default): Non-editable forms.
  • search: An afform with an embedded SearchKit Display and optional search filter fields.

Afform markup

Althought angularjs offers extensive functionality it is recommended that, where possible, CiviCRM Angular forms are written using just html and CiviCRM afform markup. The reason being that there is demand to be able to render these forms using different front end libraries (eg. React) and funding is being sought to that end. If this does proceed then the first piece of work is likely to be rendering existing FormBuilder forms via React - something that would work seamlessly if no native angularjs markup is used.

The CiviCRM Afform markup includes

Type Example Notes
form embedding markup <contact-basic></contact-basic> Embed a FormBuilder form as defined in contactBasic.aff.html & contactBasic.aff.js
api 3 access markup <div af-api3="af-api3="['Contact','getsingle', {id: options.contact_id}]" af-api3-ctrl="contact"> </div> Call api v3 & assign results to variable contact
api 4 access markup <div af-api4="['Afform', 'get', {select: ['name','title','is_public','server_route', 'has_local', 'has_base'], orderBy: {name:'ASC'}}]" af-api4-ctrl="listCtrl"></div> Call api v4 & assign results to variable listCtrl