Use a twig template instead of a render array in a custom module admin page 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.

mymodule.routing.xml

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


ReadOnlyController.php

class ReadOnlyController extends ControllerBase {

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

}


mymodule.module

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


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

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




Related doc or posts


hook_theme
Form and render elements | Drupal API
Create custom twig templates for custom module
How can I programmatically display a block?
StackOverflow - Drupal 8 custom block (module) create twig template file
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.

MYMODULE.MYPAGE:
  path: '/admin/config/MYPAGE'
  defaults:
    _form: '\Drupal\MYMODULE\Form\MYFORM'
    _title: 'MYTITLE'
  requirements:
    _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' =&gt; [
      'render element' =&gt; 'form',
      'template'       =&gt; '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:

&lt;div class="foo bar"&gt;
  {{ form }}
&lt;/div&gt;




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.