Configuring web-mode with JSX
I use web-mode for editing different templates like html
, .erb
, .js.jsx
. It understands React’s JSX tags also which is great because I don’t need a separate mode just for JSX.
Web mode can support plain jsx
or js.jsx
by using auto-mode-alist
function.
(require 'web-mode)
(add-to-list 'auto-mode-alist '("\\.jsx\\'" . web-mode))
Here we use auto-mode-alist
variable which associates major modes with file patterns so that when that file is opened, the major mode gets automatically activated.
The format is as follows:
(PATTERN . major-mode)
So \\.jsx\\'
matches .jsx
as well as .js.jsx
files and enables web-mode for them. It also sets content-type
as jsx
for these files so that JSX tags get highlighted and indentation for JSX works properly.
React also allows JSX in plain .js
files. My configuration for .js
files was as follows:
(add-to-list 'auto-mode-alist '("\\.js\\'" . web-mode))
But JSX tags don’t get highlighted and indentation also does not work with above configuration in plain .js
files.
This happens because content-type
is set to javascript
instead of jsx
.
This problem can be solved using adding a hook when web-mode
as suggested inthis issue.
(add-hook 'web-mode-hook
(lambda ()
(web-mode-set-content-type "jsx")
(message "now set to: %s" web-mode-content-type)))
But problem with this approach is, it sets content-type as jsx
for all files like .html
or .erb
. Due to this indentation of ERB code stopped working.
To solve this, I updated the hook as follows:
(add-hook 'web-mode-hook
(lambda ()
(if (equal web-mode-content-type "javascript")
(web-mode-set-content-type "jsx")
(message "now set to: %s" web-mode-content-type))))
Now the content-type will be set to jsx
only when original content-type is javascript
. This solved the issue completely as normal HTML and ERB files work as before and JSX tags and indentation works in plain JavaScript files.
My complete configuration of web mode can found on Github.
Update
Author of web-mode, François-Xavier Bois suggested to me that web-mode-content-types-alist
variable provided by web-mode can be used to achieve same thing.
Based on his suggestion, we can force content-type
as jsx
for files ending with .js
and .jsx
.
(setq web-mode-content-types-alist
'(("jsx" . "\\.js[x]?\\'")))
This will force web-mode’s content type as jsx
for .js
and .jsx
files. This is much cleaner than using a hook and also we are using feature designed specifically for this use case. Thanks Francois!
Happy Hacking!