monaco-themes: TextMate themes converted for the Monaco editor
Themes to be used and generated with monaco-editor in web browser
At a glance
- What is it?
- monaco-themes is a small TypeScript library and theme collection that parses TextMate theme files and converts them into the JSON format the Monaco editor expects, shipped as an npm package with ESM, CommonJS and IIFE builds. It suits anyone who wants a familiar editor theme in a web code editor, and the theme set is regenerated from upstream sources rather than hand-maintained.
- Who is it for?
- Adopt monaco-themes when you are embedding the Monaco editor in a web application and want a familiar TextMate theme rather than Monaco's built-in defaults, because the parsing step is handled for you and the theme JSON files are regenerated from their upstream sources.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the package actually does
monaco-themes is a list of theme definitions to be used with monaco-editor in the browser, and the repository description is blunter about the packaging side: themes to be used and generated with monaco-editor in web browser.
The useful part is the conversion. Monaco has its own theme format, a JSON structure describing the colours of the editor surface, the syntax tokens and the widget colours. The TextMate theme format, the `.tmTheme` files that editors like Sublime Text and TextMate use, is a different and richer format with inheritance and rules. Somebody who has spent years with a particular TextMate theme in a desktop editor wants that theme in a web editor, and `parseTmTheme` is the function that translates one into the other.
So the package is two things at once. It is a library exporting a parser, and it is a collection of ready-converted theme JSON files under the `themes/` directory that you can use without calling the parser at all.
The primary language is TypeScript, the licence is MIT, and the homepage is editor.bitwiser.in, which the README describes as an extended demo, alongside a minimal demo at bitwiser.in/monaco-themes. The last push to the default branch was on 2026-10-16, and the repository is not archived, with the package version at 0.4.8 and no GitHub releases.
Three ways to load it, and which one to pick
The API section documents three consumption paths, and they are not equally pleasant.
The recommended one is ESM. The parser is imported by name, the theme string is read, parsed, registered with Monaco and then selected:
import { parseTmTheme } from 'monaco-themes';
const tmThemeString = /* read using FileReader */
const themeData = parseTmTheme(tmThemeString);
monaco.editor.defineTheme('mytheme', themeData);
monaco.editor.setTheme('mytheme');The CommonJS variant is the same four steps with `require` instead of `import`. The third path drops the bundler entirely and uses a script tag, pulling the UMD build from unpkg:
<script
type="text/javascript"
src="https://unpkg.com/monaco-themes/dist/monaco-themes.js"
></script>
<script type="text/javascript">
var tmThemeString = /* read using FileReader */
var themeData = MonacoThemes.parseTmTheme(tmThemeString);
monaco.editor.defineTheme('mytheme', themeData);
monaco.editor.setTheme('mytheme');
</script>The global is `MonacoThemes` in that build, and the theme name is arbitrary, it is the string you pass to `defineTheme` and then to `setTheme`.
There is then a fourth route that skips the parser entirely, using the themes directly. With a modern bundler, a theme JSON file can be imported as a module and its default export handed to Monaco:
const monaco =
/* import monaco */
import('monaco-themes/themes/Monokai.json').then((data) => {
monaco.editor.defineTheme('monokai', data.default || data);
monaco.editor.setTheme('monokai');
});The `data.default || data` pattern is the detail that matters there, because depending on the bundler the JSON import arrives either as the module namespace or as the parsed object, and the expression handles both.
Without a bundler, the same theme can be fetched at runtime, which the README shows with a fetch of `/themes/Monokai.json` followed by `monaco.editor.defineTheme` and `monaco.editor.setTheme`. The README also says you can download the repository archive and extract and save the `themes` directory in your project, which is the route for a project with a strict content policy and no package registry access.
The theme set is generated, not curated
The development section explains the pipeline, and this is the part that most affects what you get.
The scripts are `pnpm download`, described as downloading theme files from source repositories, and `pnpm generate`, described as generating Monaco-compatible theme JSON files. The `prepublishOnly` script runs the build, the download and the generate in sequence, so every published release regenerates the theme set from whatever the upstream sources held at that moment.
That has a clear upside. A theme that gets a new syntax rule in its upstream repository shows up in the next release without anyone maintaining it here. The downside is equally clear, and the README does not hide it: the themes are not curated by this project, so the set is whatever the upstream sources contain, and a new release can change a theme you are using without any entry in a changelog explaining it.
The tree shows both forms of the source. There is a `themes/` directory with the generated Monaco-compatible JSON, and a `tmthemes/` directory holding the original TextMate files. The `scripts/` directory holds the two scripts that move data between them, and `src/` holds the parser that the library exports. The `index.html` and `vite.config.ts` at the top level are the demo, and `tsdown.config.ts` configures the build.
Two smaller details in the tree are worth knowing. There is a `renovate.json`, so the dependencies are updated automatically, and there are both a `pnpm-lock.yaml` and a `yarn.lock`, while the package metadata pins `packageManager` to pnpm 11.5.0. The `yarn.lock` is a leftover from before the move to pnpm, and the `.npmignore` file controls what the published tarball excludes, complementing the `files` array in the package manifest.
Build outputs and the modern tooling stack
The project uses modern tooling, and the README lists it: pnpm for package management, Vite for the local development server, tsdown for building the library, TypeScript for type safety, and Node.js v22+ with native TypeScript support.
The build outputs three formats. ESM at `dist/index.js`, CJS at `dist/index.cjs`, and an IIFE at `dist/monaco-themes.js` described as a browser-ready UMD-like format. All builds include TypeScript declarations and source maps.
The package manifest matches that. The `main` field points at the CommonJS build, `module` at the ESM build and `types` at the declarations, and the `exports` map has a root entry with separate `require` and `import` branches, each with its own types file, `.d.cts` for CommonJS and `.d.ts` for ESM. There is also a `./themes/*` subpath export mapping to the theme JSON files, which is what makes the direct import of `monaco-themes/themes/Monokai.json` work with a bundler.
The `files` array publishes `themes`, `dist`, `src` and the readme, so the TypeScript sources ship as well as the compiled output, which is unusual but harmless and occasionally useful when a consumer wants to read the parser.
One script deserves a note. The `test` script is `echo "Error: no test specified" && exit 1`, which is the npm default for a package with no tests. There is no test suite in this repository, and the dev dependencies reflect that, with no test runner among them. The dev dependencies are the Vite and tsdown build chain, the TypeScript compiler, `follow-redirects` with its types. The single runtime dependency is `fast-plist`, presumably there for reading plist-formatted theme files.
The `engines` field requires Node 22.0.0 or later, and the native TypeScript support the README mentions is why the scripts are run with `node --experimental-strip-types` rather than through a separate compile step.
Where monaco-themes is the wrong choice
The first wrong-tool case is an application that only needs one of Monaco's built-in themes. Monaco ships with several themes already, and if the one you want is among them, a parser and a package install are pure overhead. The value of this project is coverage of themes Monaco does not have, and conversion of the ones it does.
The second is a project that needs a theme Monaco cannot express. The conversion goes one way, from TextMate to Monaco, and any TextMate feature with no Monaco counterpart is dropped rather than approximated. A theme that relies heavily on features Monaco does not implement will look different, and there is no mechanism in this package for reporting that.
The third is a build that has to be reproducible over time without pinning. Because the theme set is regenerated from upstream sources at publish time, the same version of the package can contain different theme content depending on when it was published, and the same theme file in the `themes/` directory can change between two releases of the same major version line. For a product that ships a specific look, that means pinning the package version and, if it matters, vendoring the theme JSON into your own repository rather than depending on it at runtime.
The fourth is a project with a strict supply chain policy that would rather not add an npm dependency for a colour scheme. The README's own alternative covers this, downloading the repository archive and extracting the `themes` directory into the project, which gives you the JSON without the runtime code.
The alternative worth naming is writing the conversion yourself, which is plausible because the source is published and MIT licensed, and the difference in approach is that this package gives you a maintained parser and a regenerated collection, while a hand-written converter gives you exactly the behaviour you want for the themes you care about and no dependency to track.
Maintenance state, licensing and what to check
The repository is not archived, and the last push was on 2026-10-16, with the package at version 0.4.8 and no GitHub releases. The top level listing does not include a changelog file, which for a package at 0.4.8 with a public npm artefact means the release history lives on npm rather than in the tree.
The licence is MIT, stated in the README's licence section and in the package manifest, with the author as Brijesh and the homepage as editor.bitwiser.in. The MIT terms mean you can use the parser and the theme files in a commercial product, which matters for a UI component library that any company embedding Monaco might reasonably want to use.
Two things are worth checking before you commit. The first is the theme list itself, since the set is generated and the `themes/` directory is the authoritative list of what the current version actually contains. The second is the `scripts/download.ts` behaviour, because it pulls from source repositories at build time and the dev dependency on `follow-redirects` and the runtime dependency on `fast-plist` are there to handle the redirects and the plist manifests those repositories use.
The `.prettierrc` and the `tsconfig.json` are there for contributors, and the `.github/` directory holds the workflows. The `scripts/` folder contains the two Node scripts, run with the type stripping flag rather than compiled, which is a small but real simplification: the scripts are TypeScript and they execute directly on Node 22.
For an adopter, the practical first step is short. Install the package, look in `themes/` for the theme you want, and either import the JSON directly or parse a `.tmTheme` file at runtime. The parser is there for the case where you have a theme that is not in the collection, which is the more common reason to depend on the library rather than on the JSON.
Editorial conclusion
Adopt monaco-themes when you are embedding the Monaco editor in a web application and want a familiar TextMate theme rather than Monaco's built-in defaults, because the parsing step is handled for you and the theme JSON files are regenerated from their upstream sources. Do not adopt it for a Monaco application that only needs one of the default themes, since the dependency and the conversion step are pure overhead in that case, and do not treat the theme set as curated, because the `pnpm download` and `pnpm generate` scripts pull themes from source repositories rather than from a reviewed list. Before you ship, pin the version, note that Node 22 or later is required for the tooling, and check the `themes/` directory for the theme you intend to bundle.
Frequently asked questions
What does monaco-themes do and who is it for?
It is a list of theme definitions to be used with monaco-editor in the browser, and a library that parses TextMate theme files into the JSON format Monaco expects. It suits developers embedding the Monaco editor who want a familiar editor theme rather than the built-in defaults.
How do I install monaco-themes?
The README lists three options, `npm install monaco-themes`, `pnpm add monaco-themes` and `yarn add monaco-themes`. The package metadata pins the package manager to pnpm 11.5.0 and requires Node 22.0.0 or later.
How do I use a theme from monaco-themes with a bundler?
Import the theme JSON directly and pass the default export to Monaco, using `import('monaco-themes/themes/Monokai.json').then((data) => { monaco.editor.defineTheme('monokai', data.default || data); monaco.editor.setTheme('monokai'); })`. The `data.default || data` pattern covers bundlers that wrap JSON imports in a module namespace.
What is the parseTmTheme function for?
It converts a TextMate theme string into the theme data structure Monaco's `defineTheme` expects, so you can apply a `.tmTheme` file that is not in the bundled collection. The README's examples read the theme string with a FileReader, parse it, then call `monaco.editor.defineTheme` and `monaco.editor.setTheme`.
How are the themes in monaco-themes kept up to date?
They are generated rather than hand-maintained. The `pnpm download` script downloads theme files from source repositories and `pnpm generate` produces the Monaco-compatible theme JSON, and the `prepublishOnly` script runs the build, the download and the generate together, so each published release regenerates the theme set from its upstream sources.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/brijeshb42-monaco-themes)Was this useful?