ColorPicker Offset incorrect when Panels are outside of Editor Container
Hi @artf, The root issue is that we are trying to place a popover palette absolutely positioned over another element at an arbitrary location on the page. And we need to do this even when the origin element is outside of the editor container node. To meet this requirement, the popover palette can not be contained anyw...
Read full answer below βQuestion
GrapesJS version
- I confirm to use the latest version of GrapesJS
What browser are you using?
Chrome v122
Reproducible demo link
https://grapesjs.com/docs/getting-started.html#style-manager
Describe the bug
How to reproduce the bug?
- Go to the "StyleManager" section of the "Getting Started" doc from GrapeJS
- Try to use the color picker in the editor example of that section.
- Even if you add "position:relative" to .editor-canvas the color picker still calculates a wrong offset when the panels are outside of the editor container
What is the expected behavior? the color picker shows up next to the corresponding input
What is the current behavior? the relative offset is calculated incorrectly and the colorpicker sits outside of the editor window
Code of Conduct
- I agree to follow this project's Code of Conduct
Answers (4)
Hi @artf,
The root issue is that we are trying to place a popover palette absolutely positioned over another element at an arbitrary location on the page. And we need to do this even when the origin element is outside of the editor container node.
To meet this requirement, the popover palette can not be contained anywhere within an offsetParent, and further it must be at the highest z-index. Otherwise it will be subject to the visible area of it's offsetParent and ordered by the parent's z-index.
In my prior patch, it appeared to work because the example editor took up the full window, and thus, left: 0 and top: 0 inside the editor element were left: 0 and top: 0 inside the body as well, and the parent for spectrum was rooted right under the top most editor node placing it at the same coordinates.
At the time, I didn't consider that the StyleManager may not be within the editor element; and that we'd never find the root element as we climbed the tree. This resulted in the coordinates of the palette relative to the origin input being inaccurately calculated in getOffset.
In InputColor.ts we append the container for spectrum to the editor node. Which will work in instances where the editor contains the InputColor element and the palette, but not outside of it.
To resolve this, we need to move the Spectrum palette container all the way to the body instead.
var colorEl = $(`<div class="${this.ppfx}field-color-picker"></div>`);
var cpStyle = colorEl.get(0)!.style;
//var elToAppend = em && em.config ? em.config.el : '';
var elToAppend = $('body');
var colorPickerConfig = (em && em.getConfig && em.getConfig().colorPicker) || {};
That said, and as expected... appending Spectrum's parent container at the body has the cascading effect of not inheriting the editor styles either. As shown below:
vs.
We'd need to remove all of the .gjs-editor-cont parent classes in the style sheet, or replace them with something like .gjs-editor-sp and add that to the container.
Do you have any issues with these changes?
@bernesto can you check this one as it seems to be related to your changes
Yes, I see the issue. The logic needs to account for when the parent is outside of the container. Let me see what I can do there.
Thanks for reporting this, @rhoenerSBS.
Great question about ColorPicker Offset incorrect when Panels are outside of Editor Container. The recommended approach with ProseMirror is to use the event-driven API.
Start here:
- Check the GrapesJS documentation for your specific module
- Look for the
on()event listener method - Most operations can be achieved by listening to editor and component events
Common patterns:
// Listen for changes
editor.on('change', () => console.log('something changed'));
// Component lifecycle
editor.on('component:mount', (c) => console.log('component ready', c));
editor.on('component:update', (c) => console.log('component updated', c));
If you're still stuck:
- Share a minimal CodeSandbox reproduction
- Include what you've already tried
- Mention your GrapesJS version
- The community is here to help!
Related Questions and Answers
Continue research with similar issue discussions.
Issue #6365
Style Manager Fails to Interpret Descendant Selectors Correctly
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Chrome Version 131.0.6778.205 Reproducible...
Issue #5705
Component tools misalign when the editor is resized
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Chrome v122 Reproducible demo link https:/...
Issue #4097
mousePosFetcher in resizer config & change:style listener not working
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Brave V1.34.81 Reproducible demo link http...
Issue #4082
Remove some initial styles from frame canvas
GrapesJS version [X] I confirm to use the latest version of GrapesJS What browser are you using? Chrome v96 Reproducible demo link No demo...
Paid Plugins That Match This Issue
Curated by issue keywords and label relevance to help you ship faster.
Loading paid plugin recommendations...
Check the open-source GrapesJS plugins on GitHub or run a quick search in our free catalog.
Browse free plugins βPremium plugins ship with support, regular updates, and production-ready features β save days of integration work.
Browse premium plugins βRelated tutorials
In-depth guides on the same topic.
Tutorial
Find the Right GrapesJS Plugin in Seconds: Smarter Discovery Is Live
We're shipping a set of discovery upgrades. New label filters, a proper compatibility switch for GrapesJS vs Studio, one-click and a smarter sort bar.
Tutorial
GrapesJS vs Webflow vs Tilda: What to Choose for Your Business in 2026
Choosing the right website platform in 2026 is no longer just about building a site
Tutorial
GJS Market 2.0 - Donations, Tracking, Labels and Better Product Discovery
Weβve rolled out a new set of GrapesJS marketplace updates across GJS Market, focused on improving how creators distribute products
Browse Plugin Categories
Jump directly to plugin category pages on the marketplace.