Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing theme in one editor should change all editors #338

Open
fzafiroski opened this issue Jan 24, 2017 · 46 comments
Open

Changing theme in one editor should change all editors #338

fzafiroski opened this issue Jan 24, 2017 · 46 comments
Labels
feature-request Request for new features or functionality themes
Milestone

Comments

@fzafiroski
Copy link

monaco-editor: 0.8.0
Browser: Chrome
OS: Centos 7

When I have two editors in two different html DOM elements, if I dynamically change theme on one editor using updateOptions() function, theme properly changes on the editor, but the other editor takes some changes, for example font colors change but background does not.
The other editor should stay unchanged.

@alexdima
Copy link
Member

It is currently not possible to have two editors have different themes.

@alexdima alexdima added the feature-request Request for new features or functionality label Jan 24, 2017
@alexdima alexdima added this to the Backlog milestone Jan 24, 2017
@fzafiroski
Copy link
Author

The problem is that I can't dynamically change theme at all, because if I change to one editor, the other one gets messed up.

@alexdima
Copy link
Member

Is it not possible to change it on both editors?

e.g.
var editor1 = monaco.editor.create(...);
var editor2 = monaco.editor.create(...);
...
editor1.updateOptions({ theme: ... });
editor2.updateOptions({ theme: ... });

@fzafiroski
Copy link
Author

It is possible and that's the only way to do it in the current state, but that could add some unnecessary code.
What I wanted to say is that changing theme on one editor should either affect all the editors in the same way as the editor we changed theme on, or not affect them at all. This way, it just makes some changes to other editors which makes the text in them unreadable.
So I think this is more of a bug than a feature-request.

@alexdima alexdima changed the title Changing theme does not work when there are two editors Changing theme in one editor should change all editors Jan 25, 2017
@alexdima alexdima added bug Issue identified by VS Code Team member as probable bug and removed feature-request Request for new features or functionality labels Jan 25, 2017
@alexdima alexdima modified the milestones: v0.8.x, Backlog Jan 25, 2017
@waltonseymour
Copy link

Why is not possible to have multiple editors of different themes?

@jrshust
Copy link

jrshust commented Feb 28, 2017

-1 to Changing theme in one editor should change all editors

This is counter intuitive as the create editor function leads one to believe that themes should work on a per editor basis. There are many use cases (I have one right now which is broken) that require having multiple editors on a page styled differently. This also worked fine a few versions ago so not sure why it was changed... I'm interested in why the monaco-token-styles is injected globally as I would be open to working on a PR to fix this if necessary.

@alexdima alexdima modified the milestones: May 2017, Backlog Jun 7, 2017
@alexdima alexdima added the themes label Jun 8, 2017
@alexdima alexdima added feature-request Request for new features or functionality and removed bug Issue identified by VS Code Team member as probable bug labels Jun 19, 2017
@alexdima alexdima modified the milestones: Backlog, v0.9.x Jun 19, 2017
@liyann
Copy link

liyann commented Apr 8, 2018

@alexandrudima is this problem solved? I have the same problem in "monaco-editor": "^0.10.1",.

@antikus
Copy link

antikus commented Aug 31, 2018

Any updates on the issue?

@tevfik6
Copy link

tevfik6 commented Aug 31, 2018

It is very sad that such cool editor does not support multiple themes in different editors..
Are there any plan to work on this ticket?
Looking for a good news!

@alexdima
Copy link
Member

No, there are no plans to support this. The root cause is that tokens are stored with resolved colors in the text buffer and the same text buffer can be shown in two distinct editors.

@tevfik6
Copy link

tevfik6 commented Aug 31, 2018

Oh just noticed this update here, so it means that this is an architectural design... I guess it is because you ported from VS Code which is an app base editor(Like you change the theme in one it affects all the windows).
I'm sad that I'll have to move back to Ace Editor. I will be watching the repo until this feature comes.

Thanks for the updates!

@yfwz100
Copy link

yfwz100 commented Mar 11, 2019

Could colors of tokens be represented as CSS classes, so applying different colors can be achieved by applying different CSS rules?

@JPVenson
Copy link

Well there is a way to get your editors to have different themes as seen in:
https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors

It just includes an iframe -.-

@liuyike98
Copy link

liuyike98 commented Dec 23, 2021

still have this problem, i just wanna use a editor to be a terminal log box, and set a theme different from main editor

@AlmogBaku
Copy link

Hi, is there an update on this?

@xiaoqingb
Copy link

Well there is a way to get your editors to have different themes as seen in: https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors

It just includes an iframe -.-

not a good way,dirty hackQAQ

@janarvaez
Copy link

Keeping this thread alive after 5 years. This is still needed. I could even take a CSS guide on which properties to manually override.

@minzhenyu
Copy link

in the case of a local I use the editor, you then need to plug-in with an editor, the theme of the two editor will be affected

@RomanoViolet
Copy link

May the universe bless you, @zebateira
@Monaco-editor team: I am still struggling with the choice of globals that the team made. Why?

@JiaoShuaiBing
Copy link

Cannot be used in Chromium v78

@zerobytes
Copy link

There is a more pressing issue that regards this problem.
If I have an editor instance, and I set the theme of this instance to vs-dark, then in a future moment I create another editor without any theme definition, the new editor theme will redefine the theme of the first editor created.
Then, If I touch the first created editor and edit something, the dark theme will come back to both editors.
Quite simple to reproduce.
1 - Create an editor Instance
2 - Set the Theme of this editor Instance
3 - Create another editor Instance

I consider this a BUG because the new editor being created should be the one inheriting the theme definition of the previous one created because it had no theme definition on itself ever.

@panoply
Copy link

panoply commented Oct 15, 2023

Personally, I understand why this capability could be problematic. Sure, multiple themes in different editor instances would be nice but it's the equivalent of having two panes open in a single editor with each pane applying a different theme.... Sounds a little wild.

I suggest a middle ground approach, specifically for Monaco wherein opposed to allowing different themes be applied, how about allowing a small set of editor color customisations? In most cases editor background adjustment would suffice, wherein mild color differentiation is made available opposed to going down the route of supporting full fledged theming in different instances.

The current approach is iFrame and as xiaoqingb pointed out it's hacky.

EDIT

I didn't do my homework. One can already apply a different code background (if it helps anyone):

const editor = monaco.editor.create(...);
const styles = editor.getDomNode().style;

// Set the editor background color
styles.setProperty('--vscode-editor-background', '#000000');

// Set the editor line numbers/gutters
styles.setProperty('--vscode-editorGutter-background', '#000000');

@Mitunkumarsahu
Copy link

Badly needing it.... :D

Here {{name}} has a custom theme with orange token.... But on having a JSON response in right side Editor the color formating of left side single line editor is being override with right-side one's.

image

Originally It looks like...

image

can you help me ? how you changed the font color and background color of the react-monoco-editor? please its urgent

@geekeren
Copy link

geekeren commented Dec 23, 2023

The reason why changing the theme of one editor affects all editors is that Monaco creates a set of global CSS variables in the style tag of the head tag, which contains the styles of the class named "monaco-editor".

image

All Monaco editors have a div container with the class "monaco-editor". Therefore, every time you change the theme of one editor, it will create new styles for the "monaco-editor" class, which will affect all other editors.

To solve this issue, you can create a container with a specific class name for the Monaco editor, and the new ".monaco-editor" class styles should take effect within the specific scope. For example

image
image

I implemented a component named MonacoThemeScope, aiming to isolate the theme of each Monaco editor. The main idea is to create a ".monaco-editor" style within a specific container to override the global one.

            <MonacoThemeScope overrideTheme={customTheme}>
                <MonacoEditor
                theme={defaultTheme}
               ....
              />
            </MonacoThemeScope>
            <MonacoThemeScope overrideTheme={'hc-black'}>
              <MonacoEditor
                theme={defaultTheme}
               ....
              />
            </MonacoThemeScope>

the following is the source code of MonacoThemeScope:

import { IStandaloneThemeService } from 'monaco-editor/esm/vs/editor/standalone/common/standaloneTheme';
import { StandaloneServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices';
import { Registry } from 'monaco-editor/esm/vs/platform/registry/common/platform.js';
import {
  asCssVariableName,
  Extensions,
} from 'monaco-editor/esm/vs/platform/theme/common/colorRegistry';
import React, { PropsWithChildren } from 'react';

const getColorVariables = (theme: string) => {
  const colorRegistry = Registry.as(Extensions.ColorContribution);

  const allThemes = StandaloneServices.get(
    IStandaloneThemeService,
  )._knownThemes;
  const customTheme = allThemes.get(theme);
  return colorRegistry
    .getColors()
    .map(item => {
      const color = customTheme?.getColor(item.id, true);
      if (color) {
        return {
          key: asCssVariableName(item.id),
          value: color.toString(),
        };
      }
    })
    .filter(Boolean);
};

export type MonacoThemeScopeProps = PropsWithChildren<{
  overrideTheme: string;
}>;
export const MonacoThemeScope: React.FC<MonacoThemeScopeProps> = props => {
  const { overrideTheme } = props;
  const themeName = `${overrideTheme}`;

  const containerRef = React.createRef<HTMLDivElement>();
  React.useEffect(() => {
    const styleEleId = `MonacoThemeScope-theme-${themeName}`;
    let styleEle = document.getElementById(styleEleId);
    if (!styleEle) {
      styleEle = document.createElement('style');
      styleEle.id = styleEleId;
      document.head.appendChild(styleEle);
    }
    const mergedColors: Record<string, string> = {};
    [...getColorVariables('vs'), ...getColorVariables(overrideTheme)].forEach(
      ({ key, value }) => {
        mergedColors[key] = value;
      },
    );

    styleEle.innerHTML = `
    .MonacoThemeScope-theme-${themeName} .monaco-editor {
      ${Object.entries(mergedColors)
        .map(([key, value]) => `${key}: ${value}`)
        .join(';\n')};
    }
    
    `;
  }, []);
  return (
    <div className={`MonacoThemeScope-theme-${themeName}`} ref={containerRef}>
      {props?.children}
    </div>
  );
};

this is the final result:
image
image

@lancejpollard
Copy link

@geekeren excited you may have potentially found a solution to this! What is defaultTheme, is that anything special? Also, while your component successfully creates the CSS variables and scopes it, I am getting this:

Screenshot 2024-01-05 at 2 55 54 PM

That is, the style highlighted span elements have a class like mtk20 which is not scoped to monaco-editor or the CSS variables, and it uses that for color. Any ideas what I'm missing or how to get those to change?

Thanks for all the help here!

@lancejpollard
Copy link

@geekeren also, my theme is defined like this, do I need to define it differently to make this work?

// https://code.visualstudio.com/api/references/theme-color

const theme = ({
  background,
  string,
  highlight,
  cursor,
}: {
  string: string
  background: string
  highlight: string
  cursor: string
}) => ({
  base: 'vs-dark',
  inherit: true,
  rules: [
    { token: 'invalid', foreground: 'f44747' },
    { token: 'emphasis', fontStyle: 'italic' },
    { token: 'strong', fontStyle: 'bold' },

    { token: 'variable', foreground: '111111' },
    { token: 'variable.predefined', foreground: '111111' },
    { token: 'variable.parameter', foreground: '111111' },
    { token: 'constant', foreground: '111111', fontStyle: 'bold' },
    { token: 'comment', foreground: 'cccccc', fontStyle: 'italic' },
    { token: 'number', foreground: '10B981' },
    { token: 'number.hex', foreground: '10B981', fontStyle: 'bold' },
    { token: 'regexp', foreground: string },
    { token: 'annotation', foreground: 'cc6666' },
    { token: 'type', foreground: '111111', fontStyle: 'bold' },

    { token: 'delimiter', foreground: 'BBBBBB' },
    { token: 'delimiter.html', foreground: 'BBBBBB' },
    { token: 'delimiter.xml', foreground: 'BBBBBB' },

    { token: 'tag', foreground: '111111', fontStyle: 'bold' },
    { token: 'tag.id.pug', foreground: '111111', fontStyle: 'bold' },
    { token: 'tag.class.pug', foreground: '111111', fontStyle: 'bold' },
    { token: 'meta.scss', foreground: '555555' },
    { token: 'meta.tag', foreground: '555555' },
    { token: 'metatag', foreground: '555555' },
    { token: 'metatag.content.html', foreground: '555555' },
    { token: 'metatag.html', foreground: '111111', fontStyle: 'bold' },
    { token: 'metatag.xml', foreground: '111111', fontStyle: 'bold' },
    { token: 'metatag.php', fontStyle: 'bold' },

    { token: 'key', foreground: '9CDCFE' },
    {
      token: 'string',
      foreground: string,
      fontStyle: 'bold',
    },
    {
      token: 'string.key.json',
      foreground: '111111',
      fontStyle: 'bold',
    },
    {
      token: 'string.value.json',
      foreground: string,
      fontStyle: 'bold',
    },

    { token: 'attribute.name', foreground: '111111' },
    { token: 'attribute.value', foreground: string, fontStyle: 'bold' },
    {
      token: 'attribute.value.number.css',
      foreground: '10B981',
      fontStyle: 'bold',
    },
    {
      token: 'attribute.value.unit.css',
      foreground: '10B981',
      fontStyle: 'bold',
    },
    {
      token: 'attribute.value.hex.css',
      foreground: '10B981',
      fontStyle: 'bold',
    },

    { token: 'string.sql', foreground: string, fontStyle: 'bold' },

    { token: 'keyword', foreground: '555555' },
    { token: 'keyword.flow', foreground: 'C586C0', fontStyle: 'bold' },
    { token: 'keyword.json', foreground: 'CE9178', fontStyle: 'bold' },
    {
      token: 'keyword.flow.scss',
      foreground: '555555',
    },

    { token: 'operator.scss', foreground: 'BBBBBB' },
    { token: 'operator.sql', foreground: 'BBBBBB' },
    { token: 'operator.swift', foreground: 'BBBBBB' },
    { token: 'predefined.sql', foreground: 'FF00FF' },
    {
      background: x(background),
      token: '',
    },
  ],
  colors: {
    'editor.foreground': '#111111',
    'editor.background': background,
    'editor.selectionBackground': highlight,
    'editor.lineHighlightBackground': highlight,
    'editor.selectionHighlightBackground': highlight,
    'editor.wordHighlightBackground': highlight,
    'editor.wordHighlightStrongBackground': highlight,
    'editorCursor.foreground': cursor,
    'terminalCursor.foreground': cursor,
    'editorWhitespace.foreground': '#3B3A32',
    'editorIndentGuide.activeBackground': '#9D550FB0',
    'editor.selectionHighlightBorder': highlight,
    'editorBracketHighlight.foreground1': cursor,
    'editorBracketHighlight.foreground2': cursor,
    'editorBracketHighlight.foreground3': cursor,
  },
})

export default theme

function x(t: string) {
  return t.replace(/#/g, '')
}

@geekeren
Copy link

@lancejpollard it's unfortunately that the solution is not well solve the grammar highlight. the class name "mk-xxx" is dynamic generated differently in different theme.

@geekeren
Copy link

geekeren commented Jan 21, 2024

@lancejpollard the defaultTheme in my code is vs theme, or vs-dark theme, I just keep the two monaco editors' base theme is same. if they are different, the class name "mk-xxx" will be confilict

@lancejpollard
Copy link

Dang, didn't know if mk-xxx was dynamic or fixed, anyhow, here is what I landed on that works for my limited theme choice:

.MonacoThemeScope-theme-mytheme-light-violet .mtk6 {
  color: #7c3aed;
}

.MonacoThemeScope-theme .monaco-editor .bracket-highlighting-0,
.MonacoThemeScope-theme .monaco-editor .bracket-highlighting-1,
.MonacoThemeScope-theme .monaco-editor .bracket-highlighting-2 {
  color: #777777;
}

.MonacoThemeScope-theme-mytheme-light-violet .cursors-layer .cursor {
  background-color: #5b21b6;
  border-color: #5b21b6;
}

.MonacoThemeScope-theme-mytheme-light-violet
  .monaco-editor
  .view-overlays
  .current-line,
.MonacoThemeScope-theme-mytheme-light-violet
  .monaco-editor
  .selected-text {
  background-color: #ede9fe;
}

.MonacoThemeScope-theme-mytheme-light-blue .mtk6 {
  color: #2563eb;
}

.MonacoThemeScope-theme-mytheme-light-blue
  .monaco-editor
  .cursors-layer
  .cursor {
  background-color: #1e40af;
  border-color: #1e40af;
}

.MonacoThemeScope-theme-mytheme-light-blue
  .monaco-editor
  .view-overlays
  .current-line,
.MonacoThemeScope-theme-mytheme-light-blue
  .monaco-editor
  .selected-text {
  background-color: #dbeafe;
}
/*  */

.monaco-editor .lines-content {
  margin-left: 16px;
  /* margin-right: 16px; */
}

.monaco-editor .decorationsOverviewRuler {
  display: none !important;
}
/*

@lancejpollard
Copy link

lancejpollard commented Jan 22, 2024

In another thought, because Sandpack does not use Monaco (it uses CodeMirror it looks like, because CodeMirror works better on mobile it sounds like), I might switch to using CodeMirror so I only have one technology in the app, if I chose to use Sandpack one of these days for something else too.

@studylss
Copy link

studylss commented Sep 5, 2024

Any updates on the issue?

@GoncaloCamaz
Copy link

GoncaloCamaz commented Sep 19, 2024

I have run into the same issue here. In my case, I have a list component where, each list item is an expandable card with editors. That particular editor has a specific style because its wrapped by the expandable card. To add list items I have a modal where i need to have another code editor instance. However, since my modal styles are different, the colors do not match so I need another style. My problem was that since the styles are different, every time I opened the modal, the global styles were changed and then, every editor on the page had the style of the modal.

I fixed this issue by using the global keyword in my scss file. I did it like so:

.CodeEditorWrapper {
         // other styles from the wrapper
	:global {
		.monaco-editor {
			--vscode-editor-background: #{#121212};
			--vscode-editorGutter-background: #{#2a2a2a};
		}
	}
}

Please also note that I am using scss modules, so, even if I have another instances of CodeEditorWrapper with other styles, this will still work be conscious that this might not work with simple css.

@calvinusesyourcode
Copy link

calvinusesyourcode commented Nov 27, 2024

Bumping because I'm trying to solve a problem where a new editor instance causes all editors to revert back to the default theme, even though I have already called monaco.editor.defineTheme(themeName, themeData) and monaco.editor.setTheme(themeName) long before.

Partial solution is to call editor.updateOptions({ theme: currentMonacoTheme }) during the provided onMount callback, but this still leaves a momentarily flash of the ugly default white theme.

EDIT: Solved my flashing issue! The trick here, at least for @monaco-editor/react is to include the current theme in the JSX options like so as the theme:

<MonacoEditorReact
  path={path}
  options={options} // even though we have options.theme here
  theme={theme} // add this here
  language={language}
  value={value}
  beforeMount={beforeMount}
  onMount={onMount}
  onChange={onChange}
/>

EDIT2: It still flashes un-syntax-highlighted code but I think this is good enough for me for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature-request Request for new features or functionality themes
Projects
None yet
Development

No branches or pull requests