Blueprint composition
Combine blueprints when two reusable field sets belong to the same record. Embed a child when its fields belong under a related property such as author.
Combine blueprints in one form
Starting with the article blueprint, add a second blueprint for extra details, then select both in your view:
<?php
declare(strict_types=1);
namespace App\Form;
use FormCompose\Attribute\Form;
use FormCompose\Blueprint\BlueprintBuilder;
use FormCompose\Blueprint\FormBlueprint;
use FormCompose\Blueprint\FormContext;
#[Form('article_more')]
class ArticleDetailsForm extends FormBlueprint
{
public function configure(BlueprintBuilder $form, FormContext $context): void
{
$form->add('summary')->type('textarea');
}
}<?php
echo $this->Form
->form($article)
->blueprint('article')
->blueprint('article_more')
->submit('Save article');This renders the article fields followed by the summary, with one form tag and one submit button. Each blueprint keeps its own layout if it has one. Their field paths must be distinct; declaring title in both would fail at binding.
Nest a child blueprint
Use embed() for related data. Create the reusable author below, then add the embed to your existing ArticleForm::configure() hook.
<?php
declare(strict_types=1);
namespace App\Form;
use FormCompose\Attribute\Form;
use FormCompose\Blueprint\BlueprintBuilder;
use FormCompose\Blueprint\FormBlueprint;
use FormCompose\Blueprint\FormContext;
#[Form('author')]
class AuthorForm extends FormBlueprint
{
public function configure(BlueprintBuilder $form, FormContext $context): void
{
$form->add('name');
$form->add('email')->type('email');
}
}$form->embed('author', 'author');Compose an association
In embed('author', 'author'), the first argument is the property path; the second is the child's alias. Load the article's Author association before rendering the article form. The child's email then submits author[email]. The child shares its parent's form rather than opening another one.
The article blueprint already selects its own layout. Add the child to templates/element/forms/article.php where it should appear:
<?= $form->control('title') ?>
<?= $form->control('body') ?>
<?= $form->control('published') ?>
<?= $form->embedded('author') ?>Define a reusable child layout
For a shared author section, add the first snippet to AuthorForm::configure() and create the element in the second tab:
$form->template('forms/author');<?php
declare(strict_types=1);
/**
* @var \FormCompose\Blueprint\BlueprintView $form
* @var \FormCompose\Rendering\Attributes $attributes
*/
?>
<section<?= $attributes->merge(['class' => 'article-author']) ?>>
<h2>Author</h2>
<?= $form->controls(['name', 'email']) ?>
</section>The layout uses names relative to the author, without repeating author..
Conditional fields and parent overrides
After declaring the embed in the parent hook, change a child field with its qualified path:
$form->field('author.email')->label('Contact email');Use remove('author.name') to omit a declared child field. Custom layouts can check has('name') before displaying its wrapper.
Select a template for one embed
To override the child layout for one use, select a template on its declaration:
$form->embed('author', 'author')->template('forms/compact-author');Create that element using the same scoped layout API shown above. This replaces the embed() declaration; do not declare the same path twice.
For local occurrences inside an open session, ID rules, and collision handling, see blueprint rendering and the blueprint reference.