Beyond Prettier
Oxfmt uses Prettier's output as its baseline. On top of that, it ships features that Prettier does not have, or only has through plugins.
For intentional output differences that fix Prettier bugs, see Known divergences.
Built-in plugins
Popular Prettier plugins are built in, with no extra install:
sortImports- Based on
eslint-plugin-perfectionist/sort-imports - Disabled by default
- Based on
sortTailwindcss- Based on
prettier-plugin-tailwindcss - Disabled by default
- Based on
sortPackageJson- Based on
prettier-plugin-packagejson - Enabled by default
- Based on
jsdoc- Based on
prettier-plugin-jsdoc - Disabled by default
- Based on
oxfmt --migrate prettier converts their options too. See Migrate from Prettier.
JavaScript / TypeScript
Test calls
Like Prettier, Oxfmt keeps a test call's description and callback on one line, even if it exceeds printWidth. Prettier does this only for Jest / Jasmine / Playwright style calls (it, describe, test with .only / .skip, etc.). Oxfmt also recognizes:
- Vitest:
.concurrent,.sequential,.fails,.shuffle,bench Deno.test
// Oxfmt, printWidth: 80
it.concurrent("does something really long and descriptive with the formatter output", async () => {
expect(1).toBe(1);
});
// Prettier, printWidth: 80
it.concurrent(
"does something really long and descriptive with the formatter output",
async () => {
expect(1).toBe(1);
},
);TOML
Native support
.toml files are formatted natively. Prettier needs a plugin for TOML.
TOML in Markdown
+++ front matter and toml code blocks in Markdown are formatted too:
<!-- input -->
+++
a = 1
+++
```toml
b = [1,2]
```
<!-- Oxfmt -->
+++
a = 1
+++
```toml
b = [1, 2]
```Prettier leaves both as-is.
Markdown
Container directives
::: container directives (VitePress, Docusaurus, remark-directive, Pandoc) are parsed as blocks. Fence lines are kept as written, and only the content inside is formatted.
<!-- input -->
:::warning
Some **text** that is
long.
:::
<!-- Oxfmt, proseWrap: "always" -->
:::warning
Some **text** that is long.
:::
<!-- Prettier, proseWrap: "always" -->
:::warning Some **text** that is long. :::Prettier treats the fences as plain text and merges them into the paragraph, which breaks the container.
HTML
Dynamic end tags in HTML in JS
In html tagged templates (Lit, Solid, etc.), an element whose end tag is a ${} expression is formatted:
// input
const view = html`
<${Show} when=${loggedIn}>
<p>Welcome back!</p>
<button onclick=${logout}>Log out</button>
</${Show}>
`;
// Oxfmt
const view = html`
<${Show} when=${loggedIn}>
<p>Welcome back!</p>
<button onclick=${logout}>Log out</button>
</${Show}>
`;Prettier fails to parse the end tag and leaves the whole template as-is.
Vue
TypeScript in templates of lang="tsx"
In a Vue file whose <script> is lang="tsx", template expressions are parsed as TSX, as Vue's compiler does:
<!-- input -->
<script setup lang="tsx">
const a = <div />;
</script>
<template>
<p>{{ (value as Item).name }}</p>
</template>
<!-- Oxfmt -->
<script setup lang="tsx">
const a = <div />;
</script>
<template>
<p>{{ (value as Item).name }}</p>
</template>Prettier parses them as TypeScript only for lang="ts", and leaves TypeScript syntax as-is for lang="tsx".
Options
insertFinalNewline- Whether to insert a final newline at the end of the file.
- Also respects
insert_final_newlinein.editorconfig.
