Airbnb style guide with Next.js

Starting a fresh Next.js project the other day, I was happy to see that configuring eslint was part of the bootstrapping process. Where things fell short for me, was the lack of a prompt asking me which style guide I’d like to use.

I’m sure the out of the box option is sufficient enough, and definitely better than nothing, which still seems to be the norm for most people. Browsing some of the created files and seeing a file full of double quotes sent me into a frenzy to figure out how I can bring my beloved Airbnb style guide into the mix.

Create Next.js app

When creating my app with the create-next-app script, I went with the following configuration:

% npx create-next-app@latest

 What is your project named?  my-app
 Would you like to use TypeScript?  Yes
 Would you like to use ESLint?  Yes
 Would you like to use Tailwind CSS?  Yes
 Would you like to use `src/` directory?  Yes
 Would you like to use App Router? (recommended)  Yes
 Would you like to customize the default import alias (@/*)?  No
Creating a new Next.js app in /private/tmp/my-app.
Zsh

Because I went with TypeScript, there is a bit of additional setup, but not much.

Reinitializing ESLint

To get things moving in the right direction, I reinitialized eslint. When answering the prompts, I lied and told it I wasn’t using TypeScript, as saying your project is using TypeScript will strip the Airbnb style guide option from the list of “popular” style guides:

% npm init @eslint/config
 How would you like to use ESLint? · style
 What type of modules does your project use? · esm
 Which framework does your project use? · react
 Does your project use TypeScript? · No
 Where does your code run? · browser, node
 How would you like to define a style for your project? · guide
 Which style guide do you want to follow? · airbnb
 What format do you want your config file to be in? · JSON
Checking peerDependencies of eslint-config-airbnb@latest
The config that you've selected requires the following dependencies:

eslint-plugin-react@^7.28.0 eslint-config-airbnb@latest eslint@^7.32.0 || ^8.2.0 eslint-plugin-import@^2.25.3 eslint-plugin-jsx-a11y@^6.5.1 eslint-plugin-react-hooks@^4.3.0
✔ Would you like to install them now? · No / Yes
✔ Which package manager do you want to use? · npm
Installing eslint-plugin-react@^7.28.0, eslint-config-airbnb@latest, eslint@^7.32.0 || ^8.2.0, eslint-plugin-import@^2.25.3, eslint-plugin-jsx-a11y@^6.5.1, eslint-plugin-react-hooks@^4.3.0

added 4 packages, and audited 376 packages in 2s

137 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities
Successfully created .eslintrc.json file in /private/tmp/my-app
Zsh

So close, yet so far

By choosing the JSON config file format, the .eslintrc.json generated by create-next-app will be wiped clean in favor of a configuration based on the initialization options.

If you were to try to run npm run lint at this point, you’d be greeted with a whole mess of errors:

% npm run lint                                                                                                                                                                              
                                                                                                                                                                                            
> my-app@0.1.0 lint                                                                                                                                                                         
> next lint                                                                                                                                                                                 
                                                                                                                                                                                            
                                                                                                                                                                                            
  The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config                                            
                                                                                                                                                                                            
./src/app/layout.tsx                                                                                                                                                                        
1:13  Error: Parsing error: Unexpected token {                                                                                                                                              
                                                                                                                                                                                            
./src/app/page.tsx                                                                                                                                                                          
1:19  Error: Strings must use singlequote.  quotes                                                                                                                                          
5:5  Error: 'React' must be in scope when using JSX  react/react-in-jsx-scope                                                                                                               
5:5  Error: JSX not allowed in files with extension '.tsx'  react/jsx-filename-extension                                                                                                    
6:7  Error: 'React' must be in scope when using JSX  react/react-in-jsx-scope                                                                                                               
7:9  Error: 'React' must be in scope when using JSX  react/react-in-jsx-scope                                                                                                               
9:11  Error: 'React' must be in scope when using JSX  react/react-in-jsx-scope                                                                                                              
11:9  Error: 'React' must be in scope when using JSX  react/react-in-jsx-scope                                                                                                              
12:11  Error: 'React' must be in scope when using JSX  react/react-in-jsx-scope                                                                                                             
18:15  Error: `{" "}` must be placed on a new line  react/jsx-one-expression-per-line   

# And on and on...
Zsh

Reconfiguring ESLint

Since the out of the box configuration isn’t perfect, I created a mash up of what we got from create-next-app, what npm init @eslint/config generated, and some additional stuff to support TypeScript:

{
  "env": {
    "browser": true,
    "es2021": true,
    "node": true
  },
  "extends": [
    "airbnb",
    "airbnb/hooks",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:jsx-a11y/recommended",
    "next/core-web-vitals"
  ],
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "react"
  ],
  "rules":  {
    "react/jsx-filename-extension": [
      2,
      { "extensions": [".js", ".jsx", ".ts", ".tsx"] }
    ]
  }
}
.eslintrc.json

Installing missing dependencies

With our config ready to go, we still need to install one more package before things will work. This will give us the TypeScript ESLint parser:

% npm install --save-dev @typescript-eslint/eslint-plugin
                                                                                              
added 12 packages, and audited 388 packages in 995ms
                                                                                              
145 packages are looking for funding                                                          
  run `npm fund` for details                                                                  
                                                                                              
found 0 vulnerabilities  
Zsh

chore: making the linter happy

At this point, running the linter will yield a bunch of errors based on the Airbnb style guide.

% npm run lint

> my-app@0.1.0 lint
> next lint


./src/app/layout.tsx
1:31  Error: Strings must use singlequote.  quotes
2:23  Error: Strings must use singlequote.  quotes
3:8  Error: Strings must use singlequote.  quotes
5:33  Error: Strings must use singlequote.  quotes
8:10  Error: Strings must use singlequote.  quotes
9:16  Error: Strings must use singlequote.  quotes

./src/app/page.tsx
1:19  Error: Strings must use singlequote.  quotes
18:15  Error: `{" "}` must be placed on a new line  react/jsx-one-expression-per-line
18:16  Error: Strings must use singlequote.  quotes
49:25  Error: Curly braces are unnecessary here.  react/jsx-curly-brace-presence
49:26  Error: Strings must use singlequote.  quotes
50:17  Error: `{" "}` must be placed on a new line  react/jsx-one-expression-per-line
50:18  Error: Strings must use singlequote.  quotes
55:24  Error: Curly braces are unnecessary here.  react/jsx-curly-brace-presence
55:25  Error: Strings must use singlequote.  quotes
66:25  Error: Curly braces are unnecessary here.  react/jsx-curly-brace-presence
66:26  Error: Strings must use singlequote.  quotes
67:18  Error: `{" "}` must be placed on a new line  react/jsx-one-expression-per-line
67:19  Error: Strings must use singlequote.  quotes
72:24  Error: Curly braces are unnecessary here.  react/jsx-curly-brace-presence
72:25  Error: Strings must use singlequote.  quotes
83:25  Error: Curly braces are unnecessary here.  react/jsx-curly-brace-presence
# And then some...

info  - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/basic-features/eslint#disabling-rules
Zsh

Finally, I went through and cleaned up things by hand. You could certainly use something like prettier or even ESLint’s --fix option. I prefer a bit more control, so I go about it the old fashioned way.

Josh Sherman - The Man, The Myth, The Avatar

About Josh

Husband. Father. Pug dad. Musician. Founder of Holiday API, Head of Engineering and Emoji Specialist at Mailshake, and author of the best damn Lorem Ipsum Library for PHP.


If you found this article helpful, please consider buying me a coffee.