Tagged Templates
Syntax highlighting and subtle background tint for curated tagged template literals in JS/TS.
Editor-only: This extension only provides syntax highlighting and tinting in the editor. It never runs, evaluates, parses, or transforms your tagged template literals at runtime.

What it does
- Highlights the content of tagged templates using the target language grammar (e.g.,
json\
...`` uses JSON).
- Adds a theme-aware background tint and optional border to embedded regions.
- Purely editor-side: zero runtime behavior or code transformation.
Supported tags (MVP): json
, html
, css
, scss
, sql
, graphql
/gql
, yaml
/yml
, xml
, ts
, sh
/bash
.
Usage
Open a .ts/.tsx/.js/.jsx
file with tagged templates:
const j = json`{ "name": "mike", "version": "1.2.3" }`
const h = html`<div class="x">${x}</div>`
const q = sql`select * from users where id = ${id}`
For runtime safety and to make your editor aware of the tags, declare simple stubs using String.raw
. This is a great way to add named tags without changing runtime behavior (a no-op passthrough):
// e.g. src/tags.ts
export type TaggedTemplate = (strings: TemplateStringsArray, ...exprs: unknown[]) => string
export const json: TaggedTemplate = String.raw
export const html: TaggedTemplate = String.raw
export const sql: TaggedTemplate = String.raw
// add others if you use them (css, scss, graphql, yaml, xml, ts, sh, bash)
Then import and use them:
import { json, html, sql } from './tags'
const j = json`{ "name": "mike" }`
const h = html`<div>${j}</div>`
const q = sql`select * from t where id = ${42}`
All this extension cares about is the name of the tag on the template literal. It's compatible with simple passthrough tags created with String.raw
and with real tag implementations that parse/transform at runtime (for example, gql
from graphql-tag).
If you want to use other definitions of the tagged template literals (e.g. one that actually returns JSON from a json`{ foo: "bar" }`
), you can easily do so
type JsonValue = null | boolean | number | string | JsonValue[] | { [k: string]: JsonValue }
const json = (strings: TemplateStringsArray, ...exprs: unknown[]): JsonValue => {
// Build a single string, JSON-stringifying interpolations so they embed as valid JSON fragments
let combined = strings[0]
for (let i = 0; i < exprs.length; i++) {
combined += JSON.stringify(exprs[i]) + strings[i + 1]
}
// Allow a slightly lenient authoring style (unquoted keys, single quotes, trailing commas)
const normalized = normalizeToStrictJson(combined)
return JSON.parse(normalized) as JsonValue
}
function normalizeToStrictJson(input: string): string {
let s = input
// Quote unquoted object keys: { foo: 1, bar_baz: 2 } -> { "foo": 1, "bar_baz": 2 }
s = s.replace(/(\{|,)\s*([A-Za-z_][A-Za-z0-9_-]*)\s*:/g, '$1 "$2":')
// Convert single-quoted strings to double-quoted
s = s.replace(/'([^'\\]|\\.)*'/g, (match) => {
const inner = match.slice(1, -1).replace(/\\'/g, "'").replace(/\"/g, '"')
return '"' + inner.replace(/"/g, '\\"') + '"'
})
// Remove trailing commas
s = s.replace(/,\s*([}\]])/g, '$1')
return s
}
// Example:
// const value = json`{ foo: "bar" }` // -> { foo: "bar" }
Compatibility with real tag libraries
This extension works seamlessly with libraries that do more than simple passthrough at runtime. For example, gql
from graphql-tag parses GraphQL strings into an AST. The extension will still inject GraphQL syntax highlighting inside the gql\
...`` template, because it keys off the tag name:
import gql from 'graphql-tag'
const query = gql`
query User($id: ID!) {
user(id: $id) {
id
name
}
}
`
Settings
"taggedTemplates.enabled": true,
"taggedTemplates.tags": { "json": "source.json", "html": "text.html.basic", ... }
Color customization
The extension now supports per-language color customizations! Each tagged template type can have its own background and border colors.
Per-language colors
Override specific language colors via workbench.colorCustomizations
:
{
"workbench.colorCustomizations": {
// JSON tagged templates
"taggedTemplates.json.background": "#FFFFFF14",
"taggedTemplates.json.border": "#FFFFFF33",
// HTML tagged templates
"taggedTemplates.html.background": "#FF6B3514",
"taggedTemplates.html.border": "#FF6B3533",
// SQL tagged templates
"taggedTemplates.sql.background": "#4FC3F714",
"taggedTemplates.sql.border": "#4FC3F733",
// CSS tagged templates
"taggedTemplates.css.background": "#FF980014",
"taggedTemplates.css.border": "#FF980033",
// GraphQL tagged templates
"taggedTemplates.graphql.background": "#E1009814",
"taggedTemplates.graphql.border": "#E1009833",
// YAML tagged templates
"taggedTemplates.yaml.background": "#FFEB3B14",
"taggedTemplates.yaml.border": "#FFEB3B33",
// TypeScript tagged templates
"taggedTemplates.ts.background": "#3178C614",
"taggedTemplates.ts.border": "#3178C633",
// Shell tagged templates
"taggedTemplates.shell.background": "#4CAF5014",
"taggedTemplates.shell.border": "#4CAF5033",
// Default for other languages
"taggedTemplates.default.background": "#FFFFFF14",
"taggedTemplates.default.border": "#FFFFFF33"
}
}
Supported languages with distinct colors
- JSON: White/neutral tint
- HTML: Orange/brown tint
- CSS: Orange tint
- SQL: Blue tint
- GraphQL: Purple tint
- YAML: Yellow tint
- TypeScript: Blue tint
- Shell: Green tint
- XML: Red/orange tint
- Java: Red tint
- Ruby: Red tint
- Python: Blue tint
- PHP: Purple tint
- Go: Blue tint
- C#: Green tint
- Markdown: Black/white tint
- Gitignore: Red tint
- Environment variables: Brown tint
Legacy support
For backward compatibility, you can still use the old global colors (they will apply to the default category):
{
"workbench.colorCustomizations": {
"taggedTemplates.background": "#FFFFFF14",
"taggedTemplates.border": "#FFFFFF33"
}
}
Notes
- Only simple
identifier
followed by backtick is supported in MVP.
- Interpolations
${...}
are delegated back to the host language for proper highlighting.
- This extension does not evaluate, lint, or validate the embedded content; it only affects editor highlighting and tinting.
Development
Prerequisites
Setup
pnpm install
Development Commands
pnpm run build # Build the extension
pnpm run test # Run tests
pnpm run lint # Run ESLint
pnpm run format # Format code with Prettier
pnpm run package # Package extension as .vsix
pnpm lint-staged # Run lint-staged (auto-formats staged files)
Pre-commit Hooks
This project uses Husky with pre-commit hooks to ensure code quality:
- Auto-formatting: All staged files are automatically formatted with Prettier
- Linting: ESLint automatically fixes issues in staged files
- Supported files:
.js
, .jsx
, .ts
, .tsx
, .json
, .md
The hooks run automatically when you commit. If formatting or linting fails, the commit will be blocked until issues are resolved.
Versioning and Releases
This project uses Changesets to manage versioning and changelogs automatically.
Making Changes
When you make changes that should be included in a release:
- Create a changeset: Run
pnpm changeset
to create a new changeset file
- Select the type of change: Choose from
major
, minor
, or patch
- Write a description: Describe what changed and why
- Commit the changeset: The changeset file will be committed automatically
Releasing
To create a new release:
- Version packages: Run
pnpm version
to update versions and generate changelog
- Review changes: Check the generated changelog and version updates
- Publish: The GitHub Actions workflow will automatically publish when changesets are merged to main
Changeset Commands
pnpm changeset # Create a new changeset
pnpm version # Update versions and generate changelog (manual)
pnpm release:manual # Build and publish manually (if needed)
CI/CD
This project uses GitHub Actions for continuous integration and deployment:
CI and Release Workflow (.github/workflows/main.yml
)
- Runs on push to
main
/develop
branches and pull requests
- Tests against Node.js 20.x
- Runs linting, formatting checks, building, and tests
- Packages the extension and uploads artifacts
- Performs security audits
- Optimized with caching: VS Code downloads are cached to speed up test runs
- Automated releases: When merged to main, automatically creates release PRs and publishes to VS Code Marketplace
Required Secrets
To enable publishing to the VS Code Marketplace, add the following secret to your GitHub repository: