Tips / Making caret visible in dark mode

Making caret visible in dark mode

How to solve invisible caret issues in contenteditable when browser dark mode is enabled

Difficulty: Beginner
Category: browser-feature
dark-modecaretstylingcolor-schemevisibility

Problem

When browser dark mode is enabled, the caret in contenteditable elements may become invisible or poorly visible.

Solution

1. Use color-scheme Declaration

Declare support for both light and dark.

:root {
  color-scheme: light dark;
}

2. Explicit Caret Styling

Set explicit caret color to ensure visibility.

[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 child spans.

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

4. Sanitize Inline Styles

Remove inline styles from 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;
  }
}

Notes

  • Without color-scheme declaration, browsers may not recognize dark mode support
  • Child element backgrounds may hide the caret
  • Browser-injected inline styles may override dark mode CSS
Edit on GitHub