A form class by itself doesn't appear anywhere — SimpleForm is just a PHP class sitting in your module until something tells Drupal where a visitor can actually reach it. This lesson covers the two standard ways to put a form in front of a user: give it its own route (a dedicated page), or place it as a block (reusable, droppable into any region).
What you'll learn in this lesson
- How to give a form its own page via a route
- How to wrap the same form in a block plugin so it can appear anywhere
- Why the form class itself never needs to change between these two approaches
Giving a form its own route
The most direct way to display a form: a route whose controller callback is the form class itself, using Drupal's built-in _form key.
form_api_example.simple_form:
path: '/examples/form-api-example/simple-form'
defaults:
_form: '\Drupal\form_api_example\Form\SimpleForm'
_title: 'Simple Form Example'
requirements:
_permission: 'access content'
Notice this is _form, not _controller — Drupal's routing system has a dedicated shortcut specifically for forms, which handles instantiating the form class, calling \Drupal::formBuilder()->buildForm(), and rendering the result, all without you writing a controller at all.
Placing a form as a block
To let a site builder place the same form in a sidebar, a footer, or any other block region, wrap it in a block plugin whose build() method delegates to the form builder:
/**
* @Block(
* id = "simple_form_block",
* admin_label = @Translation("Simple Form block")
* )
*/
class SimpleFormBlock extends BlockBase {
public function build() {
return \Drupal::formBuilder()->getForm('Drupal\form_api_example\Form\SimpleForm');
}
}
This is the exact same getForm() call from the previous lesson — the form class has no idea whether it's being rendered on its own page or embedded in a block. That's the whole point of separating "how the form works" (the class) from "where the form appears" (the route or block wrapping it).
SimpleForm class, you never have two copies of your validation or submission logic to keep in sync. Add the form to a route AND a block simultaneously if you genuinely need both — they share every line of behavior.Quick check: you need the exact same contact form to appear both on its own dedicated page and as a sidebar block on every other page. Do you need two separate form classes? (No — one class, referenced from a routing.yml entry for the page and from a block plugin's
build()method for the sidebar. Same class, two presentation contexts.)
Key takeaways
- The
_formrouting key is a dedicated shortcut for form routes — it handles instantiation and rendering without a separate controller. - A block plugin can display any form by calling
\Drupal::formBuilder()->getForm()in itsbuild()method, using the form class's fully-qualified name as a string. - The same form class works identically whether it's reached via a route or embedded in a block — presentation and form logic are fully decoupled.
Coming up next
You've now built and displayed a form. The next lesson zooms into the render-array properties that define each individual field inside it — starting with the three you'll use constantly: #type, #title, and #default_value.