Scenario

Dark mode causes caret visibility and styling issues

When browser dark mode is enabled, contenteditable elements may experience invisible or poorly visible caret, inline style injection conflicts, background color issues, and form control styling problems. These issues are caused by missing color-scheme declarations and conflicts between browser-injected styles and custom CSS.

other
Scenario ID
scenario-browser-dark-mode

Details

When browser dark mode is enabled, contenteditable elements may experience invisible or poorly visible caret, inline style injection conflicts, background color issues, and form control styling problems.

Observed Behavior

  • Invisible caret: Caret uses currentColor or text color, making it invisible against dark backgrounds
  • Inline style injection: Browser inserts inline styles during editing that override dark mode CSS
  • Background color conflicts: Child elements with custom backgrounds interfere with caret rendering
  • Form control styling: Input placeholders, scrollbars, borders don’t switch properly to dark mode
  • Link color contrast: Default link colors have poor contrast against dark backgrounds

Browser Comparison

  • Safari: HTML-only dark mode has link color contrast issues
  • Chrome/Edge: Auto Dark Mode flag can invert colors globally, distorting content
  • Firefox: Similar issues with forced dark mode
  • All browsers: Missing color-scheme declaration causes problems

Impact

  • Poor user experience: Users cannot see where they’re typing
  • Accessibility issues: Low contrast fails accessibility guidelines
  • Visual inconsistency: Styling conflicts create jarring appearance
  • Editing difficulty: Makes editing in dark mode frustrating

Workarounds

1. Use color-scheme Declaration

Declare support for both light and dark:

:root {
  color-scheme: light dark;
}

2. Explicit Caret Styling

Ensure caret is visible:

[contenteditable="true"] {
  caret-color: var(--caret-color, white);
}

@media (prefers-color-scheme: dark) {
  [contenteditable="true"] {
    caret-color: #ffffff;
  }
}

3. Handle Child Elements

Avoid position: relative on inline spans:

[contenteditable="true"] span {
  position: static;
  /* or */
  display: inline-block;
  z-index: 0;
}

4. Override Inline Styles

Sanitize pasted content:

function sanitizeContent(html) {
  const div = document.createElement('div');
  div.innerHTML = html;
  
  // Remove inline styles
  div.querySelectorAll('[style]').forEach(el => {
    el.removeAttribute('style');
  });
  
  return div.innerHTML;
}

5. Dark Mode Media Query

Define dark mode colors:

@media (prefers-color-scheme: dark) {
  [contenteditable="true"] {
    background-color: #1a1a1a;
    color: #ffffff;
  }
  
  [contenteditable="true"]::placeholder {
    color: #888888;
  }
  
  [contenteditable="true"] a {
    color: #4a9eff;
  }
  
  [contenteditable="true"] a:visited {
    color: #9d4edd;
  }
}

6. Test with Forced Dark Mode

Simulate browser flags:

/* Fallback for forced dark mode */
@media (prefers-color-scheme: dark) {
  [contenteditable="true"] {
    filter: none; /* Prevent color inversion */
  }
}

References

Scenario flow

Visual view of how this scenario connects to its concrete cases and environments. Nodes can be dragged and clicked.

React Flow mini map

Variants

Each row is a concrete case for this scenario, with a dedicated document and playground.

Case OS Device Browser Keyboard Status
ce-0564-browser-dark-mode-caret-invisible Any Any Desktop or Laptop Any Chrome Latest US draft

Cases

Open a case to see the detailed description and its dedicated playground.

Related Scenarios

Other scenarios that share similar tags or category.

Tags: caret, css

Text caret is invisible on position:relative elements

When editing content inside an element with `position:relative`, the text caret (cursor) is completely invisible. Text can be typed and appears in the editor, but there's no visual feedback of where the insertion point is located.

2 cases
Tags: css

Background color changes behave inconsistently

Changing background color (highlighting) in contenteditable elements behaves inconsistently across browsers. Background colors may be applied as inline styles, may not persist when typing, or may interfere with text selection. The behavior differs from text color changes.

3 cases
Tags: caret

Browser zoom causes caret and selection positioning issues

When the browser is zoomed (or content is scaled via CSS transforms), caret position and text selection in contenteditable elements can become inaccurate. Clicking at a certain position places the caret elsewhere, and selection highlights may not match the visual selection.

1 case

Comments & Discussion

Have questions, suggestions, or want to share your experience? Join the discussion below.