An ESLint plugin for formatting code with oxfmt - A blazing fast formatter powered by Rust.
- ⚡️ Blazing Fast - Powered by oxfmt, written in Rust
- 🔧 Auto-fix - Automatically format code on save or via ESLint's fix command
- 🎯 ESLint Integration - Seamlessly integrates with ESLint v9+ flat config
- 📦 Zero Config - Works out of the box with sensible defaults
- 🧩 Config File Discovery - Supports
.oxfmtrc.json,.oxfmtrc.jsonc, andoxfmt.config.ts - 📝 EditorConfig Integration - Respects a subset of
.editorconfigoptions via oxfmt's strategy - 🎨 Highly Configurable - Supports all oxfmt formatting options
- 🌐 Multi-language Support - JavaScript, TypeScript, JSX, TSX and more
- ESLint:
>= 9.0.0(Only supports ESLint flat config) - Node.js:
^20.19.0 || >=22.12.0
npm install -D oxfmt eslint-plugin-oxfmtyarn add -D oxfmt eslint-plugin-oxfmtpnpm add -D oxfmt eslint-plugin-oxfmtAdd the plugin to your ESLint flat config file:
// eslint.config.mjs
import pluginOxfmt from 'eslint-plugin-oxfmt'
export default [
{
...pluginOxfmt.configs.recommended,
files: ['**/*.{js,ts,mjs,cjs,jsx,tsx}'],
},
]You can customize the formatting options by configuring the rule:
// eslint.config.mjs
import pluginOxfmt from 'eslint-plugin-oxfmt'
export default [
{
...pluginOxfmt.configs.recommended,
files: ['**/*.{js,ts,mjs,cjs,jsx,tsx}'],
rules: {
'oxfmt/oxfmt': [
'error',
{
// Plugin options
useConfig: false,
configPath: 'configs/.oxfmtrc.json',
// Formatting options
semi: false,
singleQuote: true,
tabWidth: 2,
useTabs: false,
trailingComma: 'all',
printWidth: 100,
arrowParens: 'avoid',
// File handling
ignorePatterns: ['**/dist/**', '**/.next/**'],
// JSX specific options
jsxSingleQuote: false,
bracketSameLine: false,
singleAttributePerLine: false,
// Object formatting
bracketSpacing: true,
quoteProps: 'as-needed',
objectWrap: 'preserve',
// Line endings
endOfLine: 'lf',
insertFinalNewline: true,
// Prose / HTML
embeddedLanguageFormatting: 'auto',
htmlWhitespaceSensitivity: 'css',
proseWrap: 'preserve',
// JSDoc
jsdoc: {
commentLineStrategy: 'singleLine',
lineWrappingStyle: 'greedy',
separateTagGroups: false,
},
// Vue
vueIndentScriptAndStyle: false,
// Advanced
sortImports: {
order: 'asc',
newlinesBetween: true,
},
sortPackageJson: { sortScripts: true },
sortTailwindcss: {
attributes: ['class', 'className', ':class'],
functions: ['clsx', 'cn'],
preserveDuplicates: false,
preserveWhitespace: false,
},
},
],
},
},
]All options are optional and default to sensible values.
| Option | Type | Default | Description |
|---|---|---|---|
useConfig |
boolean |
true |
Load .oxfmtrc.json, .oxfmtrc.jsonc, or oxfmt.config.ts via load-oxfmt-config (with .editorconfig merge support). Set to false to rely only on inline options. |
configPath |
string |
— | Custom path to an oxfmt config file. Resolved from ESLint cwd when set. |
Note:
cwdis taken from ESLint automatically; you usually do not need to set it manually..editorconfigmerge behavior follows oxfmt's documented strategy: https://oxc.rs/docs/guide/usage/formatter/config#editorconfig
When useConfig is true, the plugin loads config using load-oxfmt-config.
- Config discovery order (from
cwd, walking upward):.oxfmtrc.json→.oxfmtrc.jsonc→oxfmt.config.ts .editorconfigsupport: nearest.editorconfig(including section overrides) is merged into the final optionsconfigPathoverrides discovery and directly targets the specified config file- ESLint rule options generally take highest priority because inline rule options are merged after loaded config. However, when
useConfigistrue,overridesare taken from the loaded config (not from rule options).
For detailed behavior, see:
| Option | Type | Default | Description |
|---|---|---|---|
semi |
boolean |
true |
Add semicolons at the end of statements |
singleQuote |
boolean |
false |
Use single quotes instead of double quotes |
tabWidth |
number |
2 |
Number of spaces per indentation level |
useTabs |
boolean |
false |
Use tabs for indentation |
printWidth |
number |
100 |
Maximum line length for wrapping |
ignorePatterns |
string[] |
[] |
Glob patterns (relative to cwd) to skip formatting |
| Option | Type | Default | Description |
|---|---|---|---|
trailingComma |
'all' | 'es5' | 'none' |
'all' |
Where to add trailing commas |
| Option | Type | Default | Description |
|---|---|---|---|
arrowParens |
'always' | 'avoid' |
'always' |
Include parentheses around sole arrow function parameter |
| Option | Type | Default | Description |
|---|---|---|---|
jsxSingleQuote |
boolean |
false |
Use single quotes in JSX attributes |
bracketSameLine |
boolean |
false |
Put > on the same line in JSX |
singleAttributePerLine |
boolean |
false |
Force single attribute per line in JSX |
| Option | Type | Default | Description |
|---|---|---|---|
vueIndentScriptAndStyle |
boolean |
false |
Indent code inside <script> / <style> in Vue |
| Option | Type | Default | Description |
|---|---|---|---|
bracketSpacing |
boolean |
true |
Print spaces between brackets in object literals |
quoteProps |
'as-needed' | 'consistent' | 'preserve' |
'as-needed' |
When to quote object property names |
objectWrap |
'preserve' | 'collapse' | 'always' |
'preserve' |
How to wrap object literals |
| Option | Type | Default | Description |
|---|---|---|---|
endOfLine |
'lf' | 'crlf' | 'cr' |
'lf' |
Line ending character(s) |
insertFinalNewline |
boolean |
true |
Insert a newline at the end of files |
| Option | Type | Default | Description |
|---|---|---|---|
embeddedLanguageFormatting |
'auto' | 'off' |
'auto' |
Format embedded code blocks (e.g., JS-in-Vue, CSS-in-JS) |
htmlWhitespaceSensitivity |
'css' | 'ignore' | 'strict' |
'css' |
Global whitespace sensitivity for HTML-like languages |
proseWrap |
'always' | 'never' | 'preserve' |
'preserve' |
Control prose wrapping in Markdown/MDX |
Use jsdoc to enable and configure JSDoc comment formatting. Pass true to enable defaults, or pass an object for custom behavior (for example jsdoc: {}).
| Option | Type | Default | Description |
|---|---|---|---|
jsdoc.commentLineStrategy |
'singleLine' | 'multiline' | 'keep' |
'singleLine' |
Comment block style policy |
jsdoc.lineWrappingStyle |
'greedy' | 'balance' |
'greedy' |
Wrapping strategy for long descriptions |
jsdoc.addDefaultToDescription |
boolean |
true |
Append default values to @param descriptions |
jsdoc.bracketSpacing |
boolean |
false |
Add spaces inside JSDoc type braces |
jsdoc.capitalizeDescriptions |
boolean |
true |
Capitalize the first letter of tag descriptions |
jsdoc.descriptionTag |
boolean |
false |
Emit @description tag instead of inline description |
jsdoc.descriptionWithDot |
boolean |
false |
Add a trailing dot to the end of descriptions |
jsdoc.keepUnparsableExampleIndent |
boolean |
false |
Preserve indentation in unparsable @example code |
jsdoc.preferCodeFences |
boolean |
false |
Prefer fenced code blocks over 4-space indentation |
jsdoc.separateReturnsFromParam |
boolean |
false |
Add a blank line between final @param and @returns |
jsdoc.separateTagGroups |
boolean |
false |
Add blank lines between different tag groups |
Tip: jsdoc: true is equivalent to enabling JSDoc with default settings.
| Option | Type | Default | Description |
|---|---|---|---|
sortImports |
boolean | object |
disabled | Experimental import sorting configuration |
sortPackageJson |
boolean | object |
true |
Experimental package.json sorting (object form: { sortScripts?: boolean }) |
sortTailwindcss |
boolean | object |
disabled | Experimental Tailwind CSS class sorting (enable with {} for defaults) |
Use sortImports: true to enable import sorting with defaults, or pass an object to customize behavior.
Available keys:
customGroups: Ordered custom group definitions{ elementNamePattern?: string[]; groupName?: string; modifiers?: string[]; selector?: string }[]groups: Ordered group list; supports nested arrays and boundary markers like{ newlinesBetween: boolean }ignoreCase: Ignore case when sorting (defaulttrue)internalPattern: Glob patterns for internal importsnewlinesBetween: Insert blank lines between groups (defaulttrue)order:'asc' | 'desc'(default'asc')partitionByComment: Split groups by comments (defaultfalse)partitionByNewline: Split groups by blank lines (defaultfalse)sortSideEffects: Sort side-effect imports (defaultfalse)
- Boolean to toggle (default
true). - Object form:
{ sortScripts?: boolean }(defaultfalse).
Enable experimental Tailwind CSS class sorting powered by prettier-plugin-tailwindcss (set sortTailwindcss: true for defaults, or pass an object for custom options):
// eslint.config.mjs
import pluginOxfmt from 'eslint-plugin-oxfmt'
export default [
{
...pluginOxfmt.configs.recommended,
files: ['**/*.{js,ts,jsx,tsx}'],
rules: {
'oxfmt/oxfmt': [
'error',
{
sortTailwindcss: {},
},
],
},
},
]You can pass the Tailwind plugin options to control which attributes/functions are sorted or keep duplicates:
{
"sortTailwindcss": {
"attributes": ["class", "className", ":class"],
"config": "./tailwind.config.js",
"functions": ["clsx", "cn"],
"preserveDuplicates": false,
"preserveWhitespace": false,
"stylesheet": "./src/app.css"
}
}Use overrides to apply different oxfmt options per file glob (later entries win on conflicts):
// eslint.config.mjs
import pluginOxfmt from 'eslint-plugin-oxfmt'
export default [
{
...pluginOxfmt.configs.recommended,
files: ['**/*.{js,ts,jsx,tsx}'],
rules: {
'oxfmt/oxfmt': [
'error',
{
overrides: [
{
files: ['**/*.test.ts'],
excludeFiles: ['**/fixtures/**'],
options: {
semi: false,
trailingComma: 'none',
},
},
{
files: ['packages/**/src/**/*.{ts,tsx}'],
options: {
printWidth: 90,
sortImports: {
newlinesBetween: true,
},
},
},
],
},
],
},
},
]This plugin provides a single rule that formats your code using oxfmt.
- Recommended:
error - Fixable: Yes (automatically applies formatting)
- Type: Layout
Add this to your .vscode/settings.json:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
]
}oxfmt is a modern, blazing-fast formatter written in Rust as part of the Oxc project. It aims to be a drop-in replacement for Prettier with significantly better performance.
- Performance: 50-100x faster than Prettier
- Compatibility: Designed to be Prettier-compatible
- Modern: Built with modern JavaScript/TypeScript in mind
- Maintained: Part of the actively developed Oxc project