Custom Block in Drupal 8

Drupal 8 blocks example

In this article, we will see how we built custom blocks in EK management tools suite with a sample basic block in a module called 'mymodule' used for demo. It can be used to display multiple content, static or dynamic as in the example above.

Create the block script

First we will create a script that will display some content within a block. the script file will be called MyBlock.php and is placed in /mymodule/src/Plugin/Block/.

 * @file
 * Contains \Drupal\mymodule\Plugin\Block\MyBlock.
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResult;

 * Provides a 'Custom module widget' .
 * @Block(
 *   id = "my_block",
 *   admin_label = @Translation("My custom block"),
 *   category = @Translation("mymodule Widgets")
 * )

The file header will contain the namespace of the file, the dependencies and most important, the annotations that define the block for discovery (more information about this in Drupal).

For the purpose of this demo, the content of the block will be very simple:

class MyBlock extends BlockBase {
   * {@inheritdoc}
  public function build() {
  $items = array();
  $items['title'] = t('Custom block');
  $items['content'] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
          . "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
          . "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. "
          . "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
  return array(
    '#items' => $items,
    '#theme' => 'mymodule_block',
    '#attached' => array(
      'library' => array('mymodule/style'),
   * {@inheritdoc}
  protected function blockAccess(AccountInterface $account) {
    if (!$account->isAnonymous() ) {
      return AccessResult::allowed()->addCacheContexts(['']);
    return AccessResult::forbidden(); 

We set a title and content text to be displayed in the block in the build() function. This block use a theme template called "mymodule_block" and a library with custom css style. We will not cover this part here. The blockAccess()  function control the visibility of the block and restrict it to authenticated accounts.


Display block

In order to demonstrate the display of the block, we created an empty page with our /mymodule/block in mymodule.routing.yml, however, the block can be displayed in any page or region.

  path: '/mymodule/block'
    _controller: '\Drupal\mymodule\Controller\MyModuleController::BlockPage'
    _access: 'TRUE'

BlockPage() will just return an empty array in this sample module.

 * @file
 * Contains \Drupal\mymodule\Controller\MyModuleController.

namespace Drupal\mymodule\Controller;

use Drupal\Core\Controller\ControllerBase;

class MyModuleController extends ControllerBase {

    public function BlockPage() {
        return array();   


Now we can navigate to the block layout management page of Drupal 8, /admin/structure/block, and install our custom block.

We place the block in "Content" of the page and click on the button to select the custom block we created:

We click on "Place block" for the selected block and configure the block to show on our custom page:

After saving, we can now navigate to our page /mymodule/block and see the block in action:

Block configuration file

The block can be set in yml configuration file in order to be installed with the module. In order to do that, simply go to /admin/config/development/configuration/single/export to export the block configuration that we just activated:


Copy the configuration script into a file called block.block.mycustomblock.yml and place it under /mymodule/config/install; the block will be activated at installation time.


We hope this block example is useful and feel free to add your comments or suggestion.



Some errors snuck in there:

  • your access control logic is missing cacheability metadata
  • your asset library is named 'style.css', that doesn't seem right
  • we use {@inheritdoc} now, instead of "Implements \F\Q\C\N\Interface::method().".
  • the route you provided is fine as a sample route, but it's absolutely unnecessary

Add new comment

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.