Underline Node Type

Category: Formatting • Detailed implementation guide with view integration notes

Schema Definition

Schema definition for the Underline mark type:

{
  underline: {
  }
}

Model Representation

Example model representation:

{
  type: 'text',
  text: 'Underlined text',
  marks: [{ type: 'underline' }]
}

HTML Serialization

Converting model to HTML:

function serializeUnderlineMark(text, mark) {
  return '<u>' + text + '</u>';
}

HTML Deserialization

Parsing HTML to model:

function extractUnderlineMark(element) {
  if (element.tagName === 'U') {
    return { type: 'underline' };
  }
  return null;
}

View Integration

View Integration Notes: Pay special attention to contenteditable behavior, selection handling, and event management when implementing this node type in your view layer.

View integration code:

// Toggling underline
function toggleUnderline() {
  const selection = window.getSelection();
  if (!selection.rangeCount) return;
  
  const range = selection.getRangeAt(0);
  const hasUnderline = hasMarkInSelection(range, 'underline');
  
  if (hasUnderline) {
    removeMark('underline');
  } else {
    addMark({ type: 'underline' });
  }
}

Common Issues

Common Pitfalls: These are issues frequently encountered when implementing this node type. Review carefully before implementation.

Common issues and solutions:

// Issue: <u> is deprecated in some contexts
// Solution: Consider using CSS or <span> with style
function serializeUnderlineAlternative(text) {
  return '<span style="text-decoration: underline">' + text + '</span>';
}

// Issue: Underline with links
// Solution: Handle nested underline in links
function handleUnderlineInLink(link, underline) {
  // Links often have underline by default
  // May need to distinguish intentional underline
}

Implementation

Complete implementation example:

class UnderlineMark {
  constructor() {
    this.type = 'underline';
  }
  
  toDOM() {
    return ['u', 0];
  }
  
  static fromDOM(element) {
    if (element.tagName === 'U') {
      return new UnderlineMark();
    }
    return null;
  }
}