ESLint-Rules

Qwik comes with its own set of ESLint rules to help developers write better code.

โœ… Warn in 'recommended' ruleset

โœ… Error in 'recommended' ruleset

๐Ÿ”” Warn in 'strict' ruleset

๐Ÿ”” Error in 'strict' ruleset

Possible Problems

These rules are available.

Details

use-method-usage

Detect invalid use of use hooks.

useWrongFunction

Examples of correct code for this rule:

โœ“
export const Counter = component$(() => {
  const count = useSignal(0);
});
โœ“
export const useCounter = () => {
  const count = useSignal(0);
  return count;
};

Examples of incorrect code for this rule:

โœ•
export const Counter = (() => {
  const count = useSignal(0);
});

use* methods can just be used in component$ functions or inside use* hooks (e.g. useCounter).

valid-lexical-scope

Used the tsc typechecker to detect the capture of unserializable data in dollar ($) scopes.

referencesOutside

Examples of correct code for this rule:

โœ“
import { component$, useTask$, $ } from '@builder.io/qwik';
 
export const HelloWorld = component$(() => {
  const print = $((msg: string) => {
    console.log(msg);
  });
 
  useTask$(() => {
    print("Hello World");
  });
 
  return <h1>Hello</h1>;
});

Examples of incorrect code for this rule:

โœ•
import { component$, useTask$ } from '@builder.io/qwik';
 
export const HelloWorld = component$(() => {
  const print = (msg: string) => {
    console.log(msg);
  };
 
  useTask$(() => {
    print("Hello World");
  });
 
  return <h1>Hello</h1>;
});

Since Expressions are not serializable, they must be wrapped with $( ... ) so that the optimizer can split the code into small chunks.

invalidJsxDollar

Examples of correct code for this rule:

โœ“
import { component$, $ } from '@builder.io/qwik';
 
export const HelloWorld = component$(() => {
  const click = $(() => console.log());
  return (
    <button onClick$={click}>log it</button>
  );
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
 
export const HelloWorld = component$(() => {
  const click = () => console.log();
  return (
    <button onClick$={click}>log it</button>
  );
});

Event handler must be wrapped with ${ ... }.

mutableIdentifier

Examples of correct code for this rule:

โœ“
import { component$ } from '@builder.io/qwik';
 
export const HelloWorld = component$(() => {
  const person = { name: 'Bob' };
 
  return (
    <button onClick$={() => {
      person.name = 'Alice';
    }}>
      {person.name}
    </button>
  );
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
 
export const HelloWorld = component$(() => {
  let personName = 'Bob';
 
  return (
    <button onClick$={() => {
      personName = 'Alice';
    }}>
      {personName}
    </button>
  );
});

Simple values are not allowed to be mutated. Use an Object instead and edit one of its property.

loader-location

Detect declaration location of loader$.

invalidLoaderLocation

Examples of correct code for this rule:

โœ“
src/routes/product/[productId]/index.tsx
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useProductDetails = routeLoader$(async (requestEvent) => {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
});

Examples of incorrect code for this rule:

โœ•
src/components/product/product.tsx
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useProductDetails = routeLoader$(async (requestEvent) => {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
});

This is not a valid location for a route loader. It only can be used inside the src/routes folder, in a layout.tsx or index.tsx file.

missingExport

Examples of correct code for this rule:

โœ“
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useProductDetails = routeLoader$(async (requestEvent) => {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
});

Examples of incorrect code for this rule:

โœ•
import { routeLoader$ } from '@builder.io/qwik-city';
 
const useProductDetails = routeLoader$(async (requestEvent) => {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
});

The route loader function must be exported.

wrongName

Examples of correct code for this rule:

โœ“
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useProductDetails = routeLoader$(async (requestEvent) => {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
});

Examples of incorrect code for this rule:

โœ•
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const getProductDetails = routeLoader$(async (requestEvent) => {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
});

The route loader function name must start with use.

recommendedValue

Examples of correct code for this rule:

โœ“
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useProductDetails = routeLoader$(async (requestEvent) => {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
});

Examples of incorrect code for this rule:

โœ•
import { routeLoader$ } from '@builder.io/qwik-city';
 
async function fetcher() {
  const res = await fetch(`https://.../products/${requestEvent.params.productId}`);
  const product = await res.json();
  return product as Product;
}
 
export const useProductDetails = routeLoader$(fetcher);

It is recommended to inline the arrow function. This will help the optimizer make sure that no server code is leaked to the client build.

no-react-props

Disallow usage of React-specific className/htmlFor props.

prefer

Examples of correct code for this rule:

โœ“
<MyReactComponent class="foo" for="#password" />;

Examples of incorrect code for this rule:

โœ•
<MyReactComponent className="foo" htmlFor="#password" />;

Prefer class and for props over className and htmlFor.

prefer-classlist

Enforce using the classlist prop over importing a classnames helper. The classlist prop accepts an object { [class: string]: boolean } just like classnames.

preferClasslist

Examples of correct code for this rule:

โœ“
import { component$ } from '@builder.io/qwik';
import styles from './MyComponent.module.css';
 
export default component$((props) => {
  // Array syntax example
  return <div class={[
    styles.container, 
    'p-8', 
    props.isHighAttention ? 'text-green-500' : 'text-slate-500',
    { active: true}
  ]}>Hello world</div>;
 
  // Object syntax example
  return <div class={{  
    'text-green-500': props.isHighAttention,
    'p-4': true
  }}>Hello world</div>;
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
import classnames from 'classnames';
import styles from './MyComponent.module.css';
 
export default component$((props) => {
  return <div class={classnames(
    styles.container, 
    'p-8', 
    {
      'text-green-500' : props.isHighAttention,
      'text-slate-500' : !props.isHighAttention,
    },
    { active: true}
  )}>Hello world</div>;
});

The class prop should be used instead of any 3rd party lib to efficiently set classes based on an object.

jsx-no-script-url

Disallow javascript: URLs.

noJSURL

Examples of correct code for this rule:

โœ“
<button onClick$={() => alert('open the door please')>ring</button>

Examples of incorrect code for this rule:

โœ•
<button onClick$="javascript:alert('open the door please')">ring</button>

jsx-key

Disallow missing key props in iterators/collection literals

missingIterKey

Examples of correct code for this rule:

โœ“
import { component$ } from '@builder.io/qwik';
 
export const Person = component$(() => {
  const person  = {
    firstName: 'John',
    lastName: 'Doe',
    age: 32,
  }
 
  return (
    <ul>
      {Object.keys(person).map((color) => (
        <li key={`person-${key}`}>{person[key]}</li>
      )}
    </ul>
  );
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
 
export const Person = component$(() => {
  const person  = {
    firstName: 'John',
    lastName: 'Doe',
    age: 32,
  }
 
  return (
    <ul>
      {Object.keys(person).map((color) => (
        <li>{person[key]}</li>
      )}
    </ul>
  );
});

Missing key prop for element in iterator.

missingIterKeyUsePrag

Examples of correct code for this rule:

โœ“
import { component$ } from '@builder.io/qwik';
import Card from './Card';
import Summary from './Summary';
 
export const Person = component$(() => {
  const person  = {
    firstName: 'John',
    lastName: 'Doe',
    age: 32,
  }
 
  return (
    {Object.keys(person).map((color) => (
      <Fragment key={`person-${key}`}>
        <Card value={person[key]} />
        <Summary value={person[key]} />
      </Fragment>
    )}
  );
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
import Card from './Card';
import Summary from './Summary';
 
export const Person = component$(() => {
  const person  = {
    firstName: 'John',
    lastName: 'Doe',
    age: 32,
  }
 
  return (
    {Object.keys(person).map((color) => (
      < key={`person-${key}`}>
        <Card value={person[key]} />
        <Summary value={person[key]} />
      </>
    )}
  );
});

Missing key prop for element in iterator. The key prop allows for improved rendering performance. Shorthand fragment syntax does not support providing keys. Use <Fragment> instead

missingArrayKey

Examples of correct code for this rule:

โœ“
import { component$ } from '@builder.io/qwik';
 
export const ColorList = component$(() => {
  const colors = ['red', 'green', 'blue'];
 
  return (
    <ul>
      {colors.map((color) => (
        <li key={`color-${color}`}>{color}</li>
      )}
    </ul>
  );
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
 
export const ColorList = component$(() => {
  const colors = ['red', 'green', 'blue'];
 
  return (
    <ul>
      {colors.map((color) => (
        <li>{color}</li>
      )}
    </ul>
  );
});

Missing key prop for element in array. The key prop allows for improved rendering performance.

missingArrayKeyUsePrag

Examples of correct code for this rule:

โœ“
import { component$, Fragment } from '@builder.io/qwik';
 
export const ColorList = component$(() => {
  const colors = ['red', 'green', 'blue'];
 
  return (
    {colors.map((color) => (
      <Fragment key={`color-${color}`}>
        <h2>{color}</h2>
        <p>The color "${color}" is a great color.</p>
      </Fragment>
    )}
  );
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
 
export const ColorList = component$(() => {
  const colors = ['red', 'green', 'blue'];
 
  return (
    {colors.map((color) => (
      < key={`color-${color}`}>
        <h2>{color}</h2>
        <p>The color "${color}" is a great color.</p>
      </>
    )}
  );
});

Missing key prop for element in array. The key prop allows for improved rendering performance. Shorthand fragment syntax does not support providing keys. Use <Fragment> instead

nonUniqueKeys

Examples of correct code for this rule:

โœ“
import { component$ } from '@builder.io/qwik';
 
export const ColorList = component$(() => {
  const colors = ['red', 'green', 'blue'];
 
  return (
    <ul>
      {colors.map((color) => (
        <li key={`color-${color}`}>{color}</li>
      )}
    </ul>
  );
});

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
 
export const ColorList = component$(() => {
  const colors = ['red', 'green', 'blue'];
 
  return (
    <ul>
      {colors.map((color) => (
        <li key="not-a-good-idea">{color}</li>
      )}
    </ul>
  );
});

The key prop must be unique.

unused-server

Detect unused server$() functions.

unusedServer

Examples of correct code for this rule:

โœ“
import { component$ } from '@builder.io/qwik';
import { server$ } from '@builder.io/qwik-city';
 
const serverGreeter = server$((firstName: string, lastName: string) => {
  const greeting = `Hello ${firstName} ${lastName}`;
  return greeting;
});
 
export default component$(() => (
    <button
      onClick$={async () => {
        const greeting = await serverGreeter('John', 'Doe');
        alert(greeting);
      }}
    >
      greet
    </button>
  );
);

Examples of incorrect code for this rule:

โœ•
import { component$ } from '@builder.io/qwik';
import { server$ } from '@builder.io/qwik-city';
 
const serverGreeter = server$((firstName: string, lastName: string) => {
  const greeting = `Hello ${firstName} ${lastName}`;
  return greeting;
});
 
export default component$(() => (
    <button
      onClick$={async () => {
        const greeting = 'not using the server$ function';
        alert(greeting);
      }}
    >
      greet
    </button>
  );
);

A server$ function is declared, but never used.

jsx-img

For performance reasons, always provide width and height attributes for <img> elements, it will help to prevent layout shifts.

noLocalSrc

Examples of correct code for this rule:

โœ“
import Image from '~/media/image.png';
<Image />

Examples of incorrect code for this rule:

โœ•
<img src="/image.png">

Serving images from public are not optimized, nor cached. Import images using ESM instead.

noWidthHeight

Examples of correct code for this rule:

โœ“
<img width="200" height="600" src="/static/images/portrait-01.webp">

Examples of incorrect code for this rule:

โœ•
<img src="/static/images/portrait-01.webp">

For performance reasons, always provide width and height attributes for <img> elements, it will help to prevent layout shifts.

jsx-a

For a perfect SEO score, always provide href attribute for <a> elements.

noHref

no-use-visible-task

Qwik tries very hard to defer client code execution for as long as possible. This is done to give the end-user the best possible user experience. Running code eagerly blocks the main thread, which prevents the user from interacting until the task is finished. "useVisibleTask$" is provided as an escape hatch.
When in doubt, instead of "useVisibleTask$()" use:
  • useTask$ -> perform code execution in SSR mode.
  • useOn() -> listen to events on the root element of the current component.
  • useOnWindow() -> listen to events on the window object.
  • useOnDocument() -> listen to events on the document object.
Sometimes it is the only way to achieve the result.
In that case, add:
// eslint-disable-next-line qwik/no-use-visible-task
to the line before "useVisibleTask$" to acknowledge you understand.