cellStates (active/selected) backColor alpha not compositing over cell's backco

Posted by: averma on 11 August 2026, 1:10 am EST

    • Post Options:
    • Link

    Posted 11 August 2026, 1:10 am EST

    COMPONENT

    GC.Spread.Sheets.CellStatesType (active, selected) / sheet.cellStates.add API

    VERSION

    @mescius/spread-sheets 18.2.3

    SUMMARY

    Cell with explicit backColor set via setStyle becomes fully hidden when cell enters

    active or selected state, even when cellStates style backColor has an alpha channel

    set well below 100%. Expected: cell’s own backColor shows through, tinted by the

    overlay color. Actual: overlay fully opaque, cell color invisible while

    selected/active.

    REPRO STEPS

    1. Set a cell’s style backColor to solid color, e.g.
      #FF6B6B
      :
    const testStyle = new GC.Spread.Sheets.Style();
    testStyle.backColor = '#FF6B6B';
    sheet.setStyle(2, 2, testStyle, GC.Spread.Sheets.SheetArea.viewport);
    2. Register cellStates active/selected styles (colors as currently used in our app):
    ```js
    const activeStyle = new GC.Spread.Sheets.Style();
    activeStyle.backColor = isDark ? '#FFFFFF12' : '#EDE6FF';
    
    const selectedStyle = new GC.Spread.Sheets.Style();
    selectedStyle.backColor = isDark ? '#40268C4D' : '#D9C7FF26';
    
    const fullRange = new GC.Spread.Sheets.Range(-1, -1, -1, -1);
    sheet.cellStates.add(fullRange, GC.Spread.Sheets.CellStatesType.active, activeStyle);
    sheet.cellStates.add(fullRange, GC.Spread.Sheets.CellStatesType.selected, selectedStyle);
    
    3. Click cell (2,2) — active state. Observe: red fully hidden.
    4. Select range including (2,2) — selected state. Observe: red fully hidden.
    5. Note: light-mode active color `#EDE6FF` has no alpha byte at all (fully opaque
       by design) — expected to hide the cell. But dark-mode active (`#FFFFFF12`,
       ~7% alpha) and both selected colors (`#40268C4D` ~30%, `#D9C7FF26` ~15%) DO
       carry alpha, and still fully hide the underlying red — this is the actual bug.
    6. Retested with alpha lowered further (down to `#05FF0000`, ~2%) — no visible
       change, overlay remains opaque at all alpha levels tested.
    7. Retested with alpha byte moved to the other position (alpha-last vs
       alpha-first) — same opaque result both ways.
    
    EXPECTED
    Cell's own backColor should show through the active/selected overlay, blended per
    the alpha value set on the cellStates style — consistent with how
    `selectionBackColor`/range-selection tint is documented to behave elsewhere.
    
    ACTUAL
    Overlay paints fully opaque regardless of alpha value or byte order, completely
    masking the cell's own backColor.
    
    QUESTION FOR SPREADJS TEAM
    1. Is alpha compositing supported for `cellStates.add` backColor, or does the
       engine always paint it as a full replacement (not a blend)?
    2. If supported, confirm exact hex format expected (`#AARRGGBB` vs `#RRGGBBAA`)
       for v18.2.3 specifically — prior ticket response (see [ref old ticket #]) said
       alpha-first, but our testing shows no compositing in either order.
    3. Is there a different/recommended API to tint a cell's existing backColor on
       selection while preserving visibility, if cellStates doesn't support it?
    
    ENVIRONMENT
    - @mescius/spread-sheets 18.2.3
    - React/TS, embedded as Atlassian Forge macro (Confluence)
    - Repro is isolated to plain SpreadJS API calls, not app-specific
  • Posted 11 August 2026, 5:16 am EST - Updated 11 August 2026, 5:21 am EST

    Hi,

    SpreadJS uses an HTML5 Canvas. Based on our investigation, the behavior can be explained as follows:

    cellStates operates at the style cascade level

    When a cell enters a state such as active, selected, or hover, SpreadJS evaluates the state priority chain:

    edit > hover > active > selected > invalid formula > dirty > invalid > readonly

    When a cell state defines a backColor, that color replaces the cell’s base backColor within the style cascade for that render frame.

    Why the cell’s original backColor is not visible

    For example, if the cell’s original backColor is #FF6B6B and the active cell state specifies a semi-transparent color such as #FFFFFF12 (approximately 7% alpha), the original red background is not rendered first.

    Instead, the cell-state backColor replaces the original background in the style cascade. Therefore, when the canvas painter renders the semi-transparent color, it is composited against the underlying sheet/viewport background rather than against the cell’s original red background.

    This can make it appear as though an opaque layer is covering the cell. In reality, the original cell backColor was not included in that render pass.

    Why selectionBackColor behaves differently

    sheet.options.selectionBackColor is rendered through a separate selection overlay pass after the cells have already rendered their base styles, including their original backColor.

    Therefore, alpha compositing works as expected with selectionBackColor, allowing the underlying cell color to remain visible through the selection tint.

    Answers to your questions

    Question 1: Does cellStates.add support alpha compositing over an existing cell backColor?

    No. cellStates.add does not provide layer-based alpha blending over the cell’s existing backColor.

    The backColor specified through cellStates is treated as a property replacement within the cell style cascade, rather than as an additional canvas overlay layer. As a result, any alpha channel in the cell-state backColor is composited against the underlying sheet background rather than the cell’s original backColor.

    Question 2: What is the correct 8-digit hexadecimal color format in SpreadJS v18.2.3?

    SpreadJS follows the standard CSS/HTML5 Canvas color format. For 8-digit hexadecimal colors, the format is:

    #RRGGBBAA

    where the last two characters represent the alpha value.

    For example:

    #40268C4D → Red: 40, Green: 26, Blue: 8C, Alpha: 4D (approximately 30% opacity)

    #AARRGGBB is not the standard CSS/Canvas format.

    Alternatively, you can use the rgba() format, for example:

    rgba(64, 38, 140, 0.3)

    Please note that changing the color format does not change the rendering behavior of cellStates. The behavior is related to how cellStates applies the backColor within the style cascade.

    Question 3: Is there a recommended API to tint an existing cell backColor while preserving its visibility?

    Yes. If your goal is to apply a semi-transparent tint to selected cells while allowing their existing background colors to remain visible, we recommend using sheet.options.selectionBackColor.

    Recommended approach: selectionBackColor

    For example:

    const isDark = true;
    
    const spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"));
    const sheet = spread.getActiveSheet();
    
    const testStyle = new GC.Spread.Sheets.Style();
    testStyle.backColor = '#FF6B6B';
    sheet.setStyle(2, 2, testStyle, GC.Spread.Sheets.SheetArea.viewport);
    
    sheet.options.selectionBackColor = isDark ? 'rgba(64, 38, 140, 0.3)' : 'rgba(217, 199, 255, 0.15)';
    sheet.options.selectionBorderColor = isDark ? '#40268C' : '#D9C7FF';

    With this approach, selectionBackColor acts as an overlay, so the underlying cell backColor remains visible while the selection tint is applied on top.

    Refer to the attached sample: Sample.zip

    Gif:

    If you encounter any issues while using this approach, please share a minimal working sample along with the steps to reproduce the behavior. Alternatively, you can modify the existing sample to demonstrate the issue. This will help us investigate the problem more thoroughly. Additionally, a GIF or video showing the issue would be helpful.

    If this approach does not meet your requirements, please provide more details about your exact use case, along with some examples of the expected behavior. This will help us better understand your requirements and suggest an appropriate solution.

    Regards,

    Priyam

  • Posted 19 August 2026, 9:05 am EST

    const themeSheetLight = useCallback(

    (sheet: GC.Spread.Sheets.Worksheet, assets: ThemeAssets) => {

    sheet.setDefaultStyle(assets.defaultStyle, GC.Spread.Sheets.SheetArea.viewport);

    sheet.setDefaultStyle(assets.headerStyle, GC.Spread.Sheets.SheetArea.rowHeader);

    sheet.setDefaultStyle(assets.headerStyle, GC.Spread.Sheets.SheetArea.colHeader);

    const isDark = theme.palette.mode === 'dark';
    
    // Overlay pass (post cell-render) — per SpreadJS support, this is
    // the ONLY API that composites alpha over the cell's own backColor.
    // cellStates.add was confirmed NOT to do this (replaces backColor
    // in the style cascade pre-render, composites against sheet bg
    // instead of cell bg). Ticket ref: [paste ticket # here].
    sheet.options.selectionBackColor = isDark
      ? 'rgba(64, 38, 140, 0.3)'
      : 'rgba(217, 199, 255, 0.15)';
    sheet.options.selectionBorderColor = theme.palette.custom.cell.selectedCellBorder;
    

    },

    [theme.palette.mode, theme.palette.custom.cell.selectedCellBorder],

    );

    here i want #EDE6FF in light mode for single selected cell, and #FFFFFF12 in dark mode for single selected cell. text should not hide

  • Posted 20 August 2026, 9:02 am EST

    Hi Ashish,

    We tested the recommended approach using selectionBackColor with the colors from your example.

    One important distinction is that selectionBackColor is rendered as a selection overlay. Therefore, the alpha value affects how much of the content underneath the overlay remains visible.

    In your case:

    • Light mode: #EDE6FF is fully opaque because it does not specify an alpha value.
    • Dark mode: #FFFFFF12 has approximately 7% opacity, so the content underneath remains visible.

    If the text/content needs to remain visible while using the light-mode selection color, we recommend using a light-mode color with an alpha value as well, for example:

    sheet.options.selectionBackColor = isDark ? '#FFFFFF12' : '#EDE6FFCC';

    This allows the underlying cell rendering to remain partially visible while still providing the desired selection tint.

    Please let us know if you encounter any further issues or require additional assistance.

    Thanks & Regards,

    Chirag

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels