I'd like to add some CSS directives that:

  1. Will effect the entire site (hence "global").
  2. Will not be dependent in any theme whatsoever.

I should add these CSS directives directly from the GUI, without editing any file with a text editor like Visual Studio Code or Nano.

The module CSS editor allows me to add such CSS from the GUI per theme, but I need a broader way --- independent of any theme.


I found the non-GUI approach of GiorgosK's answer best in practice as it requires minimal time and effort to operate, saving these to some other tasks.

  • @JohnDoea, a suggestion, you can following module color to do this. Some task you need to do.1. Define a library by hook_library_info_alter 2, Use hook_page_attachments to add style to every page. 3, Create a form allow user add css like module CSS editor. 4, Process when form submitted (create css file from input value, Invalidate cache tag library_info) – MrD Sep 5 '18 at 3:53

I think you should create your own module for this lets call it global_css

add your css global.css inside css folder

and define it as a library in global_css.libraries.yml

  version: 1.x
      css/global.css: {}

and attach this library to all pages in your global_css.module

function global_css_page_attachments(array &$page) {
  $page['#attached']['library'][] = 'global_css/global-css-library';

For more details


Implementation Plan:

  • Implement the hook_library_info_build to construct the dynamic library definition.
  • Implement the hook_preprocess_page to attach the dynamic library.
  • Create a custom form to allow the provide the UI to the users, so that users can upload the CSS file and change the related CSS parameters.
  • Create a route in order to have an URL where to display your form.
  • Create a menu link, so that users can navigate to your form.
  • Enable the module.

Reference implementation:

Custom Form

file: src/Form/GlobalCSSForm.php

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Cache\Cache;
use Drupal\file\Entity\File;

 * Implements form controller.
class GlobalCSSForm extends ConfigFormBase {

   * {@inheritdoc}
  public function buildForm(array $form, FormStateInterface $form_state) {

    $config = $this->config('mymodule.global_css');

    $form['description'] = [
      '#type' => 'item',
      '#markup' => $this->t('The CSS file that you upload will be attached to all pages.'),

    $form['css_content'] = [
      '#type' => 'textarea',
      '#title' => $this->t('CSS Content'),
      '#default_value' => $config->get('css_content'),

    $form['group'] = [
      '#type' => 'select',
      '#title' => $this->t('CSS Group'),
      '#options' => [
        'base' => $this->t('Base'),
        'layout' => $this->t('Layout'),
        'component' => $this->t('Component'),
        'state' => $this->t('State'),
        'theme' => $this->t('Theme'),
      // '#empty_option' => $this->t('-select-'),
      '#default_value' => 'theme',
      '#description' => $this->t('Controls the group where the file will be placed'),

    $form['weight'] = [
      '#type' => 'number',
      '#title' => $this->t('Weight'),
      '#description' => $this->t('Controls the positioning of the file within the rest of CSS files in the group.'),
      '#default_value' => '999',

    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),

    return parent::buildForm($form, $form_state);

   * {@inheritdoc}
  public function getFormId() {
    return 'mymodule_global_css_config_form';

   * {@inheritdoc}
  protected function getEditableConfigNames() {
    return [

   * {@inheritdoc}
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Get form values.
    $css_content = $form_state->getValue('css_content');
    $group = $form_state->getValue('group');
    $weight = $form_state->getValue('weight');

    $file_uri = file_unmanaged_save_data($css_content, "public://mymodule--global-style.css", FILE_EXISTS_REPLACE);
    $path = parse_url(file_create_url($file_uri))['path'];
    $config = $this->config('mymodule.global_css');

    // Save the file ID in the configuration.
    $config->set('css_content', $css_content)
      ->set('file_path', $path)
      ->set('group', $group)
      ->set('weight', $weight)

    // Notify the user.
    $messenger = \Drupal::messenger();
    $messenger->addMessage(t('CSS file saved on the server, the URL is "%url"',
        ['%url' => file_create_url($file_uri)])

    // Invalidate the cache.

Module file

file: mymodule.module

 * Implements hook_library_info_build().
function mymodule_library_info_build() {
  $config = \Drupal::configFactory()->get('mymodule.global_css');
  $path = $config->get('file_path');
  $group = $config->get('group');
  $weight = $config->get('weight');

  $libraries = [];
  if ($path && $group && $weight) {
    $libraries['global_css'] = [
      'css' => [
        $group => [
          $path => ['weight' => $weight],
    return $libraries;
  return [];

 * Implements hook_library_info_alter().
function mymodule_preprocess_page(&$variables) {
  // Add a custom cache tag.
  $variables['#cache']['tags'][] = 'mymodule_global_css';
  // Add our dynamic library. Otherwise hook_library_info_build won't be called.
  $variables['#attached']['library'][] = 'mymodule/global_css';


file: mymodule.routing.yml

  path: '/admin/global-css'
    _form:  '\Drupal\mymodule\Form\GlobalCSSForm'
    _title: 'Global CSS Form'
    _permission: 'administer site configuration'

Menu Link

file: mymodule.links.menu.yml

  title: 'Mymodule Global CSS'
  route_name: 'mymodule.global_css_config_form'
  menu_name: admin
  parent: system.themes_page
  weight: -100

Module Info

file: mymodule.info.yml

name: 'mymodule'
type: module
description: 'An example module mymodule...'
package: 'mymodule'
core: 8.x
  • @vinhdv, thank you, I was misunderstanding the 'directly from the GUI' part. I just changed the widget. – Cesar Moore Sep 5 '18 at 23:47
  • 2
    @JohnDoea, I think my submission is good now. I also got confused by the phrase 'without editing any file with a text editor like Visual Studio Code or Nano', I was thinking you meant 'without editing the source code at the *.libraries.yml file'. The widget is a textarea now. – Cesar Moore Sep 5 '18 at 23:49

Since the question was changed to include directly from the GUI here is another way to do it

Create a custom block by going to structure > block layout > add custom block > basic block (/block/add/basic) and add your style as FULL HTML

<style type="text/css">
body {
  background: red;

enter image description here

And add this block to the footer (or any other region) of ALL available THEMES

  • This should affect the whole page and site. You'll need to add the block to each theme, including any admin theme if you want the styles to apply to admin pages. Test it using the "body" example given in GiorgosK's answer. – imclean Sep 5 '18 at 23:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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