Prettier ConfigPrettier Config

embeddedLanguageFormatting β€” formatting the CSS, HTML and GraphQL hiding inside your template literals

The Prettier Embedded Language Formatting option

embeddedLanguageFormatting decides whether Prettier formats code embedded inside another language β€” the CSS in a styled-component, the GraphQL in a gql tag, the JavaScript in a Markdown code fence. The default auto formats it when it can identify it confidently.

Control how Prettier formats quoted code embedded in the file.
Prettier's own description, from the official options documentation
Default
"auto"
Type
choice
CLI flag
--embedded-language-formatting
Allowed values
autooff

What the option does

With auto (the default), Prettier looks for template literals and code blocks whose language it can recognise, parses the contents with the appropriate parser, and formats them in place. With off, embedded content is left exactly as written.

const Button = styled.button`
  color: red;
  padding: 4px 8px;
`;
The CSS inside this tagged template is formatted by Prettier.

How Prettier decides what is embedded

Recognition is heuristic, and knowing the heuristics explains most surprises:

  • Tag name. styled.foo, styled(Component), css, createGlobalStyle and keyframes are treated as CSS; gql and graphql as GraphQL; html as HTML; markdown as Markdown.
  • A leading block comment. /* CSS */, /* HTML */ or /* GraphQL */ immediately inside the backtick tells Prettier the language explicitly. This is the escape hatch when your tag has a name Prettier does not know.
  • Markdown fences. A fenced block labelled with a language Prettier supports is formatted with that parser.
const styles = myCustomTag/* CSS */ `
  color: red;
`;
The comment form, for a tag Prettier would not otherwise recognise.

When to turn it off

  • When a template literal contains something that only looks like CSS or GraphQL, and Prettier mangles it or fails to parse it.
  • When interpolations make the embedded content syntactically invalid on its own β€” heavy ${...} use inside a CSS block is the usual culprit.
  • When the embedded formatting produces diffs you do not want in files you otherwise need Prettier to touch.

Turning it off globally is a blunt instrument. Prefer a targeted // prettier-ignore on the offending literal, or an overrides block scoped to the files that need it, so the rest of the codebase keeps the benefit.

Common mistakes

  • Assuming any template literal containing CSS will be formatted. Without a recognised tag or a language comment, Prettier leaves it alone.
  • Setting off to fix one broken literal, losing formatting across every styled-component in the project.
  • Expecting Markdown code fences to be formatted when the fence has no language label β€” the label is what selects the parser.
  • Expecting embedded formatting to apply inside ordinary strings. It only applies to template literals and fenced blocks.

Why interpolations are the usual failure

Embedded formatting works by extracting the literal's contents and handing them to another parser. A template with ${...} holes is not, on its own, valid CSS or GraphQL β€” so Prettier substitutes placeholders, formats, and substitutes back.

That works when the interpolation sits where a value or a declaration would go. It fails when the interpolation spans structure β€” a hole containing a whole block, a selector and its braces, or a conditional that emits different numbers of declarations:

const Box = styled.div`
  color: red;
  ${(p) => p.active && `
    border: 1px solid;
    padding: 8px;
  `}
`;
The interpolation spans a block boundary, so the contents no longer parse as CSS.

When that happens Prettier leaves the literal alone rather than producing broken output. If you see one styled-component formatted and its neighbour untouched, this is usually why β€” and it is a signal that the component might be clearer with the conditional pulled out into a named fragment.

A note on plugins and performance

Embedded formatting invokes a second parser per literal, so a file with hundreds of styled-components is measurably slower to format than the same file with embeddedLanguageFormatting: "off". On a normal codebase the difference is not worth thinking about; on a generated file with thousands of literals it can be.

Plugins can register their own embedded languages, so the set of recognised tags is not fixed. If you have added a plugin and a literal has started being formatted that previously was not, the plugin is the reason.

Use it in .prettierrc

Drop embeddedLanguageFormatting into your Prettier config file:

{
  "embeddedLanguageFormatting": "auto"
}
Try it in the generator

Allowed values

auto
Format embedded code if Prettier can automatically identify it.
off
Never automatically format embedded code.

Common questions

Why is the CSS in my template literal not formatted?
Prettier did not recognise the tag. Use a known tag such as css or styled.x, or add a /* CSS */ comment immediately after the tag and before the backtick.
How do I stop it formatting one particular literal?
Put // prettier-ignore on the line before it. Setting embeddedLanguageFormatting: "off" disables the feature everywhere, which is usually more than you want.
Does it format code blocks in Markdown?
Yes, when the fence carries a language label Prettier supports. An unlabelled fence is left alone.

Other Global options

Generated from Prettier 3.9.6.