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.

Stay tuned

Join 1,000+ subscribers and receive monthly tips & updates on new Ariakit content.

No spam. Unsubscribe anytime. Read latest issue