formatItalic

How formatItalic inputType applies italic formatting and varies across browsers.

Overview

The formatItalic inputType is triggered when the user presses Ctrl/Cmd + I. The browser wraps selected text in an italic element (<em> or <i>).

Basic Behavior

Scenario 1: Text selected within paragraph

Before (Text selected)

HTML:
<p>Hello world text</p>

After Cmd/Ctrl + I (Chrome/Edge)

HTML:
<p>Hello <em>world</em> text</p>
Uses <em> element

After Cmd/Ctrl + I (Firefox)

HTML:
<p>Hello <i>world</i> text</p>
Uses <i> element

Toggle Behavior

Scenario 2: Already italic text selected

Before (Italic text selected)

HTML:
<p>Hello <em>world</em> text</p>

After Cmd/Ctrl + I (Removes italic)

HTML:
<p>Hello world text</p>
Removes <em> wrapper

Collapsed Selection (Cursor Position)

⚠️ Critical Edge Case

When the selection is collapsed, pressing Cmd/Ctrl + I toggles italic state for the next character to be typed. input event typically does not fire.

IME Composition + formatItalic

⚠️ Critical Issue

During IME composition, pressing Cmd/Ctrl + I may not work as expected:

  • macOS + Korean IME: formatItalic does not fire; insertCompositionText may fire instead
  • Other platforms: beforeinput may not fire, only input fires (cannot prevent)

See formatBold for detailed workarounds.

Browser-Specific Differences

Element Used for Italic

Chrome/Edge

  • Uses <em> element

Firefox

  • Uses <i> element

Safari

  • Uses <em> element

Editor-Specific Handling

Different editor frameworks handle italic formatting similarly to bold formatting. Here's how major editors implement formatItalic:

Slate.js

Italic Formatting

Slate uses Transforms.setNodes() to toggle italic marks:

    import { Editor, Transforms, Text } from 'slate';

function isItalicActive(editor: Editor) {
  const marks = Editor.marks(editor);
  return marks?.italic === true;
}

function handleFormatItalic(editor: Editor) {
  const isActive = isItalicActive(editor);
  Transforms.setNodes(
    editor,
    { italic: !isActive },
    { match: n => Text.isText(n), split: true }
  );
}

element.addEventListener('beforeinput', (e) => {
  if (e.inputType === 'formatItalic') {
    e.preventDefault();
    handleFormatItalic(editor);
  }
});
  
  • Mark-based: Formatting stored as { italic: true } on text nodes.
  • Same pattern as bold: Uses identical Transforms API as formatBold.
ProseMirror

Italic Formatting

ProseMirror uses toggleMark with em mark:

    import { toggleMark } from 'prosemirror-commands';
import { schema } from './schema';

function handleFormatItalic(state, dispatch) {
  return toggleMark(schema.marks.em)(state, dispatch);
}

view.dom.addEventListener('beforeinput', (e) => {
  if (e.inputType === 'formatItalic') {
    e.preventDefault();
    const { state, dispatch } = view;
    if (handleFormatItalic(state, dispatch)) {
      // Handled
    }
  }
});
  
  • Mark system: Uses schema.marks.em instead of strong.
  • Same command: Uses toggleMark() like bold formatting.
Draft.js

Italic Formatting

Draft.js uses RichUtils.toggleInlineStyle() with ITALIC:

    import { EditorState, RichUtils } from 'draft-js';

function handleFormatItalic(editorState) {
  return RichUtils.toggleInlineStyle(editorState, 'ITALIC');
}

function myKeyBindingFn(e) {
  if (e.keyCode === 73 && (e.ctrlKey || e.metaKey)) {
    return 'italic';
  }
  return getDefaultKeyBinding(e);
}

function handleKeyCommand(command) {
  if (command === 'italic') {
    const newState = handleFormatItalic(editorState);
    setEditorState(newState);
    return 'handled';
  }
  return 'not-handled';
}
  
  • Inline style: Uses 'ITALIC' style string.
  • Same utility: Uses RichUtils.toggleInlineStyle like bold.

Related resources