Ariakit
/

Coding guidelines

Best practices we follow when writing Ariakit code examples for documentation purposes.

Overview

This document provides guidelines for writing code examples in Ariakit documentation. It serves as a reference for our preferred coding style, but it is not a general guide for writing code in your own app.

Feel free to consult this document for insights into our approach to code writing.

This is a living document, and certain code examples on the site might not be current. If you find any outdated examples, please submit a pull request to have them updated.

Prefer interface over type

When using TypeScript to define prop types for components, we use interface instead of type. This is because interface syntax supports extends, which allows us to properly extend other types.

If you use the type keyword with intersection (&), it may silently introduce unintended or invalid types, which would be immediately detected if you used interface instead:

// ❌ Bad, produces an invalid type without error
type CheckboxProps = React.ComponentPropsWithoutRef<"input"> & {
onChange?: (value: boolean) => void;
}
// ❗ Interface immediately detects the error
interface CheckboxProps extends React.ComponentPropsWithoutRef<"input"> {
onChange?: (value: boolean) => void;
}
// ✅ Good, fixed
interface CheckboxProps
extends Omit<React.ComponentPropsWithoutRef<"input">, "onChange"> {
onChange?: (value: boolean) => void;
}

JSDoc is also better merged with interface. For example, tags such as @default will be appropriately overridden, whereas type would duplicate them.

In summary, according to the TypeScript documentation, it is recommended that you use interface until you need to use features from type.

Name functions inside forwardRef

When wrapping components with React.forwardRef, we pass a named function as an argument instead of an anonymous arrow function. This is because React DevTools uses the function name to determine the component's name, eliminating the need to set displayName:

// ❌ Bad
export const Combobox = React.forwardRef<HTMLInputElement, Props>(
(props, ref) => {
// ...
}
);
// ❌ Bad
Combobox.displayName = "Combobox";
// ✅ Good
export const Combobox = React.forwardRef<HTMLInputElement, Props>(
function Combobox(props, ref) {
// ...
}
);

Import namespace

When importing components from Ariakit and the import statement expands to multiple lines, we use the namespace import syntax instead. This improves code readability and makes it more concise.

// ❌ Bad (for documentation, but fine for app code)
import {
} from "@ariakit/react";
// ✅ Good
import * as Ariakit from "@ariakit/react";
// ✅ Good
import { Checkbox } from "@ariakit/react";

This also simplifies the creation of abstractions for Ariakit components. For instance, when developing a custom Combobox component, there's no need to rename the Ariakit Combobox to a different name.

However, this isn't a strict rule for documentation. If it results in cleaner code overall, it makes more sense to import components individually, even if the import statement spans multiple lines.

Import .jsx extension

The code examples are written using the ECMAScript modules syntax, which is the official standard format for JavaScript modules supported by modern browsers.

One difference between ESM and CommonJS is that ESM requires the file extension to be specified in the import statement. For TypeScript React files, you can use either .js or .jsx extensions.

When importing .tsx files, we use the .jsx extension for consistency and better compatibility with build tools like Vite.

// ❌ Bad, non-standard
import "./component";
// ❌ Bad
import "./component.js";
// ✅ Good
import "./component.jsx";

Import style first

In our code examples, we place the import statement for styles at the top of the file. This ensures that when we edit the example, the autoimport feature will add import statements at the end of the import list. This prevents the style import from being inserted in the middle of the list.

// ❌ Bad
import { Combobox } from "@ariakit/react";
import "./style.css";
// ❌ Bad, autoimport will append the list
import { Combobox } from "@ariakit/react";
import "./style.css";
import { useState } from "react";
// ✅ Good
import "./style.css";
import { Combobox } from "@ariakit/react";
import { useState } from "react";

Follow updates

Join 1,000+ subscribers and receive monthly updates with the latest improvements on Guide.

Read latest issue

No Spam. Unsubscribe at any time.