I have a Drupal 8 custom module, and I want to display its configuration page using the admin theme.

Usually, for this kind of pages I use, in the _controller property of my route, rather :

  • a class that extends \Drupal\Core\Form\ConfigFormBase (for a simple form-like config page)
  • a custom controller that extends \Drupal\Core\Controller\ControllerBase and returns a renderable array

For this module, I need to use complex HTML structure and a Javascript library for its configuration page. Writing all this directly in a #markup property of a render array would be too much work and highly not-maintainable.

Is it possible to write a custom template (twig or not), to render it programmatically and insert the result into a container element or in a #markup property ? And, as I use the Seven admin theme, I would like to do this without affecting the theme.

[Resolved] Final solution :

Combining leymannx answer and the elements mentioned below, I ended up with something that meet my requirements.


  path: '/admin/config/mymodule/readonly'
    _controller: '\Drupal\mymodule\Controller\ReadOnlyController::index'
    _title: 'Module configuration - read only'
    _permission: 'view mymodule configuration'
    _admin_route: TRUE
    no_cache: TRUE


class ReadOnlyController extends ControllerBase {

    public function index(){
        return array(
            '#type' => 'container',
            '#theme' => 'test-template',
            '#test_var' => [ 0, 1, 2, 3 ] // I needed an array type variable



// Implements hook_theme()
function mymodule_theme( $existing, $type, $theme, $path ){
    return [
        'test-template' => [
            'render element' => 'container', // To render a simple container element
            'template' => 'test', // My template file name
            'variables' => [
                'test_var' => [] // Default value for my variable

And finally, my test template : templates/test.html.twig

<p>Hello !</p>
<!-- Just to see the content of my variable, after enabling twig debug mode -->
{{ dump(test_var) }}

Related doc or posts

1 Answer 1


The back-end theme automatically switches by path. So if your route's path begins with /admin it will show the page in the admin theme.

  path: '/admin/config/MYPAGE'
    _form: '\Drupal\MYMODULE\Form\MYFORM'
    _title: 'MYTITLE'
    _permission: 'administer site configuration'

To render a form inside your own template you could simply register a new theme implementation inside MYMODULE/MYMODULE.module.

 * Implements hook_theme().
function MYMODULE_theme($existing, $type, $theme, $path) {

  return [
    'MYNAME' => [
      'render element' => 'form',
      'template'       => 'MYTEMPLATE',

And in the form you set this as the form's #theme.

$form['#theme'] = 'MYNAME';

And in the MYMODULE/templates/MYTEMPLATE.html.tiwg template you print it like so:

<div class="foo bar">
  {{ form }}

Any additional library also can simply be #attached directly to the form.

$form['#attached']['library'][] = 'MYMODULE/MYLIBRARY';

Read More

[drupal.org] Create custom twig templates for custom module.

  • Do you know if this is adaptable to render something else than a form ?
    – Eria
    Commented Jun 18, 2018 at 12:14
  • Yupp, that's the way it goes via hook_theme.
    – leymannx
    Commented Jun 18, 2018 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.