I'm hoping this is possible. I work in a variety of environments and languages. Right now it's mostly django and Node.js, but there have been others. What I would like to do is set the web-mode engine based on the project I am currently working on, and not the file extension. I know I could use .djhtml as the file extension, but that messes things up for others who aren't using Emacs because, for example, Pycharm doesn't know what to do with a .djhtml file. I would prefer to keep my .html if at all possible.

I am wondering if there is any way to set the web-mode engine based on the project I'm working in. I'd rather not have to put -*- engine: django -*- into each of my files either, if I can avoid it.


I've tried adding the following to a .dir-locals.el file, but it doesn't seem to make a difference. I get prompted to allow the variable change, and the value of the variable web-mode-engines-alist has changed to (("django" . "\\.html\\'")), but django is not set as the template engine when I open a .html file.

((web-mode .
    ((web-mode-engines-alist .
          (("django" . "\\.html\\'"))))))


To clarify, I can set all .html files to open with the django engine by putting the following in my .spacemacs file:

(setq web-mode-engines-alist
      '(("django" . "\\.html\\'")))

That works just fine, but sets it globally, meaning I'll get the django engine in any .html file, regardless if it's a django project or another language.


  • Emacs: 25.2.1
  • OS: Windows 10

I found this bug reported in web-mode (https://github.com/fxbois/web-mode/issues/799), but it's just referred to be asked as a question here.

  • Directory local variables might be the solution for you: gnu.org/software/emacs/manual/html_node/emacs/…
    – user12563
    May 4 '17 at 21:36
  • I don't know why it's not working. But to get rid of the prompting for the variable change you need to update safe-local-variable-values.
    – njdan5691
    May 5 '17 at 13:33
  • I get the prompt to allow safe-local-variable-values when I load it up. That doesn't fix the problem, though.
    – Ryan
    May 5 '17 at 13:47
  • Do you know that the regexps associated with auto-mode-alist work on the (full) path not just the filename ? If you want a setting by project, it might be the solution. There is an example on web-mode.org
    – fxbois
    May 10 '17 at 15:49
  • @fxbois I don't want to have to each of my projects to my init.el. It seems like dir-locals.el would be the way to do this, but for some reason web-mode isn't recognizing it.
    – Ryan
    May 11 '17 at 19:39

Have you tried adding a web-mode-hook to check if you are in a projectile project? You would also have to check if the projectile project is a django one, but I am not that familiar with django.

(defun cesco/django ()
    (if (projectile-project-p)
        (if (file-exists-p (concat (projectile-project-root) "manage.py"))
            (web-mode-set-engine "django")
            (message "do not exists") ;; You can safely delet this line
(add-hook 'web-mode-hook 'cesco/django)
  • Though I, too, recommend use-package, it might be helpful for non-users to suggest the vanilla equivalent of this: (add-to-list 'auto-mode-alist '("\\.html\\'" . django-mode))
    – Basil
    May 8 '17 at 12:53
  • I don't want to use the django-mode. I just want to use web-mode's django engine.
    – Ryan
    May 8 '17 at 13:52
  • @Ryan I am just guessing here. I dont do django and use web-mode to typescript dev only
    – CESCO
    May 8 '17 at 13:57
  • I also only want to use the django engine for .html files if I'm working on a Django project. From the looks of it, this will switch it for all .html files. I tried using this snippet in the dir-locals.el file for the project, but that didn't work.
    – Ryan
    May 8 '17 at 14:14
  • 1
    Passing an unquoted alist to progn is malformed lisp - the interpreter will try to call the first car (in this case web-mode) as a function, which I doubt is desirable. Passing a quoted alist to progn is a no-op. The alist should probably be assigned to some variable or passed to some function.
    – Basil
    May 8 '17 at 14:17

I have found a solution thanks to this recipe: https://www.emacswiki.org/emacs/LocalVariables .

I set a custom variable in .dir-locals:

((nil . ((mik-web-mode-engine . "django")))
 (python-mode (pyvenv-activate . "../pyenv/api_bo"))
 (mhtml-mode . ((mik-web-mode-engine . "django")
                (mode . web))))

Then I read it from a hook defined in my init file:

;; web-mode
(defun my-web-mode-hook ()
  "Hooks for Web mode. Add a local hook which set the engine to the one specified by
   `mik-web-mode-engine` local variable."
   (lambda ()
     (if (boundp 'mik-web-mode-engine)
           (message "web-mode-engine is %s" mik-web-mode-engine)
           (web-mode-set-engine mik-web-mode-engine))
         (message "no web-mode-engine settled")
         (web-mode-set-engine "none"))))))
(add-hook 'web-mode-hook  'my-web-mode-hook nil nil)

Note that I switch from mhtml-mode (the default on my setup) to web-mode. If you have defined web-mode as the default for HTML you don't need that.

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.