Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions docs/contributors/code/coding-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ Examples of styles that appear in both the theme and the editor include gallery

## JavaScript

@aduth aduth Aug 17, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered updating this title to something like "JavaScript (TypeScript)", "JavaScript / TypeScript", or just "TypeScript", but I also don't want to break any existing links to this section of the documentation. GitHub allows renaming an anchor via <a name> so we could preserve existing anchor, but I'm not sure this would work in how the documentation is mirrored into the developer site.

And frankly, I don't think it's wrong to continue titling the section "JavaScript", as ultimately JavaScript continues to be the basis of the language we write (TypeScript being a superset). And who knows, maybe some day this will be JavaScript syntax 🤷


All new code in Gutenberg should be written in [TypeScript](https://www.typescriptlang.org/), with a `.ts` file extension, or a `.tsx` file extension for files including JSX syntax.

There are some exceptions where writing plain JavaScript (`.js`) is permitted:

- If the code is expected to be run directly in the browser or by Node.js in environments where TypeScript syntax is not supported. Note that as of Node.js v22.18.0 and newer, [TypeScript files containing erasable syntax can be executed directly by the Node.js runtime](https://nodejs.org/learn/typescript/run-natively).
- If authoring new code in an existing `.js` or `.jsx` file. Migrating existing files to the equivalent `.ts` or `.tsx` is encouraged if it is trivial to do so.
- If authoring new files in a package which is largely untyped, such that the new file would not have reasonable access to existing package typings.

JavaScript in Gutenberg uses modern language features of the [ECMAScript language specification](https://www.ecma-international.org/ecma-262/) as well as the [JSX language syntax extension](https://react.dev/learn/writing-markup-with-jsx). These are enabled through a combination of preset configurations, notably [`@wordpress/babel-preset-default`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/babel-preset-default) which is used as a preset in the project's [Babel](https://babeljs.io/) configuration.

While the [staged process](https://tc39.es/process-document/) for introducing a new JavaScript language feature offers an opportunity to use new features before they are considered complete, **the Gutenberg project and the `@wordpress/babel-preset-default` configuration will only target support for proposals which have reached Stage 4 ("Finished")**.
Expand Down Expand Up @@ -535,15 +543,16 @@ It is preferred to implement all components as [function components](https://rea

## JavaScript documentation using JSDoc

Gutenberg follows the [WordPress JavaScript Documentation Standards](https://make.wordpress.org/core/handbook/best-practices/inline-documentation-standards/javascript/), with additional guidelines relevant for its distinct use of [import semantics](/docs/contributors/code/coding-guidelines.md#imports) in organizing files, the [use of TypeScript tooling](/docs/contributors/code/testing-overview.md#javascript-testing) for types validation, and automated documentation generation using [`@wordpress/docgen`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/docgen).
Gutenberg follows the [WordPress JavaScript Documentation Standards](https://make.wordpress.org/core/handbook/best-practices/inline-documentation-standards/javascript/), with additional guidelines relevant for its distinct use of [import semantics](/docs/contributors/code/coding-guidelines.md#imports) in organizing files, and automated documentation generation using [`@wordpress/docgen`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/docgen).

For additional guidance, consult the following resources:

- [JSDoc Official Documentation](https://jsdoc.app/index.html)
- [TypeScript Supported JSDoc](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
For additional guidance, consult the [JSDoc Official Documentation](https://jsdoc.app/index.html).

### Custom types

<div class="callout callout-warning">
Prefer defining types using TypeScript syntax when possible. This guidance applies to files which have not yet been migrated to TypeScript.
</div>

Define custom types using the [JSDoc `@typedef` tag](https://jsdoc.app/tags-typedef.html).

A custom type should include a description, and should always include its base type.
Expand Down Expand Up @@ -579,6 +588,10 @@ Note the use of quotes when defining a set of string literals. As in the [JavaSc

### Importing and exporting types

<div class="callout callout-warning">
Prefer importing and exporting types using TypeScript syntax when possible. This guidance applies to files which have not yet been migrated to TypeScript.
</div>

Use the [TypeScript `import` function](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#import-types) to import type declarations from other files or third-party dependencies.

Since an imported type declaration can occupy an excess of the available line length and become verbose when referenced multiple times, you are encouraged to create an alias of the external type using a `@typedef` declaration at the top of the file, immediately following [the `import` groupings](/docs/contributors/code/coding-guidelines.md#imports).
Expand Down Expand Up @@ -611,6 +624,10 @@ For packages which do not distribute their own TypeScript types, you are welcome

### Generic types

<div class="callout callout-warning">
Prefer annotating types using TypeScript syntax when possible. This guidance applies to files which have not yet been migrated to TypeScript.
</div>

When documenting a generic type such as `Object`, `Function`, `Promise`, etc., always include details about the expected record types.

```js
Expand Down Expand Up @@ -661,6 +678,10 @@ const BREAKPOINTS = { huge: 1440 /* , ... */ };

### Nullable, undefined, and void types

<div class="callout callout-warning">
Prefer using TypeScript types when possible. This guidance applies to files which have not yet been migrated to TypeScript.
</div>

You can express a nullable type using a leading `?`. Use the nullable form of a type only if you're describing either the type or an explicit `null` value. Do not use the nullable form as an indicator of an optional parameter.

```js
Expand Down Expand Up @@ -758,6 +779,10 @@ When documenting an example, use the markdown <code>\`\`\`</code> code block to

### Documenting React components

<div class="callout callout-warning">
Component prop types should be written using TypeScript syntax when possible. This guidance applies to files which have not yet been migrated to TypeScript.
</div>

When possible, all components should be implemented as [function components](https://react.dev/learn/your-first-component), using [hooks](https://react.dev/reference/react/hooks) for managing component lifecycle and state.

Documenting a function component should be treated the same as any other function. The primary caveat in documenting a component is being aware that the function typically accepts only a single argument (the "props"), which may include many property members. Use the [dot syntax for parameter properties](https://jsdoc.app/tags-param.html#parameters-with-properties) to document individual prop types.
Expand Down Expand Up @@ -797,9 +822,9 @@ GitHub Actions workflows operate in a privileged software supply chain environme

These files are statically scanned when modified using [Actionlint](https://github.com/rhysd/actionlint) and [Zizmor](https://github.com/zizmorcore/zizmor). Actionlint scans the YAML workflow files within the `.github/workflows` directory, while Zizmor additionally scans any action file (`action.yml`) located anywhere in the repository. It's recommended that you install both of these tools locally using a package manager to run prior to submitting changes to workflow or action files.

- [GitHub Actions Workflow Standards for WordPress](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/github-actions/)
- [Actionlint installations instructions](https://github.com/rhysd/actionlint/blob/main/docs/install.md)
- [Zizmor installation instructions](https://docs.zizmor.sh/installation/)
- [GitHub Actions Workflow Standards for WordPress](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/github-actions/)
- [Actionlint installations instructions](https://github.com/rhysd/actionlint/blob/main/docs/install.md)
- [Zizmor installation instructions](https://docs.zizmor.sh/installation/)

To run Actionlint:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,4 +299,4 @@ For other editors, see [Prettier's Editor Integration docs](https://prettier.io/

### TypeScript

**TypeScript** is a typed superset of JavaScript language. The Gutenberg project uses TypeScript via JSDoc to [type check JavaScript files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html). If you use Visual Studio Code, TypeScript support is built-in, otherwise see [TypeScript Editor Support](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support) for editor integrations.
[**TypeScript**](https://www.typescriptlang.org/) is a typed superset of JavaScript language. The Gutenberg project uses TypeScript to detect type-based errors and improve developer experience through editor integrations. If you use Visual Studio Code, TypeScript support is built-in, otherwise see [TypeScript Editor Support](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support) for editor integrations.
1 change: 0 additions & 1 deletion packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,6 @@ If you are publishing new versions of packages, note that there are versioning r
## TypeScript

The [TypeScript](https://www.typescriptlang.org/) language is a typed superset of JavaScript that compiles to plain JavaScript.
Gutenberg does not use the TypeScript language, however TypeScript has powerful tooling that can be applied to JavaScript projects.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗑️


Gutenberg uses TypeScript for several reasons, including:

Expand Down
15 changes: 7 additions & 8 deletions packages/components/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ function HookExample() {

## TypeScript

We strongly encourage using TypeScript for all new components.
All new components should be written in TypeScript.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to update the folder structure in this file, since it mentions creating index.js files?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to update the folder structure in this file, since it mentions creating index.js files?

I updated .js file extensions to .ts in 425a55c. Interestingly many of the folder structure examples were already .ts and .tsx, so these remaining few address the inconsistency.


Extend existing components’ props if possible, especially when a component internally forwards its props to another component in the package:

Expand Down Expand Up @@ -680,9 +680,9 @@ As a result of the above guidelines, all new components (except for shared utili
```text
component-name/
├── stories
│ └── index.js
│ └── index.ts
├── test
│ └── index.js
│ └── index.ts
├── component.tsx
├── context.ts
├── hook.ts
Expand All @@ -709,9 +709,9 @@ component-family-name/
│ ├── README.md
│ └── style.module.scss
├── stories
│ └── index.js
│ └── index.ts
├── test
│ └── index.js
│ └── index.ts
├── context.ts
├── index.ts
├── types.ts
Expand Down Expand Up @@ -753,19 +753,18 @@ If possible, the legacy version of the component should be rewritten so that it
function LegacyComponent( props ) {
const newProps = useTranslateLegacyPropsToNewProps( props );

return ( <NewComponentImplementation { ...newProps } /> );
return <NewComponentImplementation { ...newProps } />;
}

// new-component/index.tsx
function NewComponent( props ) {
return ( <NewComponentImplementation { ...props } /> );
return <NewComponentImplementation { ...props } />;
}

// new-component/implementation.tsx
function NewComponentImplementation( props ) {
// implementation
}

```

In case that is not possible (eg. too difficult to reconciliate new and legacy implementations, or impossible to preserve backward compatibility), then the legacy implementation can stay as-is.
Expand Down
Loading