Text Editor

Framework7 comes with a touch-friendly Rich Text Editor component. It is based on modern "contenteditable" API so it should work everywhere as is.

It comes with the basic set of formatting features. But its functionality can be easily extended and customized to fit any requirements.

Text Editor Layout

<div class="text-editor">
  <div class="text-editor-content" contenteditable></div>
</div>

To make editor resizable (when its height will fit to its content), we need to add text-editor-resizable class to editor element:

<!-- additional "text-editor-resizable" class -->
<div class="text-editor text-editor-resizable">
  <div class="text-editor-content" contenteditable></div>
</div>

Text Editor App Methods

Let's look at related App methods to work with Text Editor:

app.textEditor.create(parameters)- create Text Editor instance

  • parameters - object. Object with Text Editor parameters

Method returns created Text Editor instance

app.textEditor.destroy(el)- destroy Text Editor instance

  • el - HTMLElement or string (with CSS Selector) or object. Text Editor element or Text Editor instance to destroy.

app.textEditor.get(el)- get Text Editor instance by HTML element

  • el - HTMLElement or string (with CSS Selector). Text Editor element.

Method returns Text Editor's instance

For example:

var textEditor = app.textEditor.create({
  el: '#my-text-editor',
  value: <code><p>Hello</p></code>,
});

Text Editor Parameters

Let's look on list of all available Text Editor parameters:

ParameterTypeDefaultDescription
elHTMLElement
string
Text Editor element. HTMLElement or string with CSS selector of editor element
valuestring

Text editor initial html content value. Initial value can also be placed as inner HTML content of text-editor-content element, e.g.:

<div class="text-editor">
  <div class="text-editor-content" contenteditable>
    <p>Initial HTML value</p>
  </div>
</div>
placeholderstringEditor placeholder content displayed when it is empty. By default it is not specified
modestringtoolbar

Text editor buttons mode. Can be:

  • toolbar - it will add toolbar with editor buttons in text editor container element
  • popover - it will show popover bubble with editor buttons on top of the selected text in editor
  • keyboard-toolbar - toolbar with editor buttons will appear on top of virtual keyboard when editor is in the focus. It is supported only in iOS, Android cordova apps and in Android Chrome. When not supported it will fallback to popover mode.
buttonsarray

Array with editor buttons, or array of arrays (groups) with editor buttons. By default all buttons enabled and its default value is:

[
  ['bold', 'italic', 'underline', 'strikeThrough'],
  ['orderedList', 'unorderedList'],
  ['link', 'image'],
  ['paragraph', 'h1', 'h2', 'h3'],
  ['alignLeft', 'alignCenter', 'alignRight', 'alignJustify'],
  ['subscript', 'superscript'],
  ['indent', 'outdent'],
]
dividersbooleantrueAdds visual divider between buttons group
imageUrlTextstringInsert image URLPrompt text that appears on image url request
linkUrlTextstringInsert link URLPrompt text that appears on link url request
clearFormattingOnPastebooleantrueWhen enabled it will clear any formatting on paste from clipboard
customButtonsobject

Object with custom buttons. Object property key is the button id that should be used in buttons to enable it.

For example to specify custom button that will add <hr> we can use following declaration:

var textEditor = app.textEditor.create({
  el: '.my-text-editor',
  customButtons: {
    // property key is the button id
    hr: {
      // button html content
      content: '&lt;hr&gt;',
      // button click handler
      onClick(event, buttonEl) {
        document.execCommand('insertHorizontalRule', false);
      }
    }
  },
  // now we use custom button id "hr" to add it to buttons
  buttons: ['bold', 'italic', 'hr']
})
onobject

Object with events handlers. For example:

var textEditor = app.textEditor.create({
  ...
  on: {
    change: function () {
      console.log('Text Editor value changed')
    }
  }
})

Note that all following parameters can be used in global app parameters under textEditor property to set defaults for all text editors. For example:

var app = new Framework7({
  textEditor: {
    buttons: ['bold', 'italic'],
  }
});

Text Editor Methods & Properties

After we initialize Text Editor we have its initialized instance in variable (like textEditor variable in examples above) with helpful methods and properties:

Properties
textEditor.appLink to global app instance
textEditor.elText Editor container HTML element
textEditor.$elDom7 instance with Text Editor container HTML element
textEditor.contentElText Editor content (contenteditalbe) HTML element
textEditor.$contentElDom7 instance with Text Editor content (contenteditalbe) HTML element
textEditor.valueHTML value of the Text Editor
textEditor.paramsObject with initialization parameters
Methods
textEditor.setValue(value)Set new Text Editor value. value is the HTML string.
textEditor.getValue()Returns current Text Editor value
textEditor.clearValue()Clear Text Editor value
textEditor.getSelectionRange()Returns current selection Range
textEditor.setSelectionRange(range)Set selection based on passed Range
textEditor.destroy()Destroy Text Editor instance and remove all events
textEditor.on(event, handler)Add event handler
textEditor.once(event, handler)Add event handler that will be removed after it was fired
textEditor.off(event, handler)Remove event handler
textEditor.off(event)Remove all handlers for specified event
textEditor.emit(event, ...args)Fire event on instance

Text Editor Events

Text Editor will fire the following DOM events on text editor element and events on app andtext editor instance:

DOM Events

EventDescription
texteditor:initEvent will be triggered when on editor initialization
texteditor:changeEvent will be triggered when editor value has been changed
texteditor:inputEvent will be triggered on editor's content "input" event
texteditor:focusEvent will be triggered on editor's content focus
texteditor:blurEvent will be triggered on editor's content blur
texteditor:buttonclickEvent will be triggered on editor button click
texteditor:keyboardopenEvent will be triggered when editor keyboard toolbar appears
texteditor:keyboardcloseEvent will be triggered when editor keyboard toolbar disappears
texteditor:popoveropenEvent will be triggered on editor popover open
texteditor:popovercloseEvent will be triggered on editor popover close
texteditor:beforedestroyEvent will be triggered right before Text Editor instance will be destroyed

App and Text Editor Instance Events

Text Editor instance emits events on both self instance and app instance. App instance events has same names prefixed with textEditor.

EventTargetArgumentsDescription
inittextEditor(editor)Event will be triggered when on editor initialization.
textEditorInitapp
changetextEditor(editor)Event will be triggered when on editor initialization.
textEditorChangeapp
inputtextEditor(editor)Event will be triggered on editor's content "input" event.
textEditorInputapp
focustextEditor(editor)Event will be triggered on editor's content focus.
textEditorFocusapp
blurtextEditor(editor)Event will be triggered on editor's content blur.
textEditorBlurapp
buttonClicktextEditor(editor, button)Event will be triggered on editor button click.
As second argument event handler receives id of the clicked button, e.g. bold
textEditorButtonClickapp
keyboardOpentextEditor(editor)Event will be triggered when editor keyboard toolbar appears.
textEditorKeyboardOpenapp
keyboardClosetextEditor(editor)Event will be triggered when editor keyboard toolbar disappears.
textEditorKeyboardCloseapp
popoverOpentextEditor(editor)Event will be triggered on editor popover open.
textEditorPopoverOpenapp
popoverClosetextEditor(editor)Event will be triggered on editor popover close.
textEditorPopoverCloseapp
beforeDestroytextEditor(editor)Event will be triggered right before Text Editor instance will be destroyed.
textEditorBeforeDestroyapp

Text Editor Auto Initialization

If you don't need to use Text Editor API and your Text Editor is inside of the page and presented in DOM on moment of page initialization then it can be auto initialized with just adding additional text-editor-init class:

<!-- Add text-editor-init class -->
<div class="text-editor text-editor-init">
  <div class="text-editor-content" contenteditable></div>
</div>

In this case if you need to access created Text Editor instance you can use the app.textEditor.get app method:

var textEditor = app.textEditor.get('.my-text-editor');

if (!textEditor.value) {
  // do something
}

When using auto init you may need to pass additional parameters. It can be done with data- attributes on panel element.

<!-- parameters set via data- attributes -->
<div
  class="text-editor text-editor-init"
  data-mode="popover"
  data-placeholder="Description"
>
  ...
</div>

Parameters used in camelCase, for example imageUrlText, in data- attributes should be used in kebab-case as data-image-url-text

CSS Variables

Below is the list of related CSS variables (CSS custom properties).

:root {
  --f7-text-editor-font-size: inherit;
  --f7-text-editor-font-weight: inherit;
  --f7-text-editor-border-width: 1px;
  --f7-text-editor-height: 250px;
  --f7-text-editor-margin: 16px;
  --f7-text-editor-padding: 8px;
  --f7-text-editor-button-bg-color: transparent;
  --f7-text-editor-button-size: 28px;
  --f7-text-editor-button-icon-size: 20px;
  --f7-text-editor-button-margin: 2px;
  --f7-text-editor-text-color: #000;
  --f7-text-editor-bg-color: #fff;
  --f7-text-editor-button-divider-color: rgba(0, 0, 0, 0.15);
}
:root .dark,
:root.dark {
  --f7-text-editor-bg-color: #121212;
  --f7-text-editor-text-color: #fff;
  --f7-text-editor-button-divider-color: rgba(255, 255, 255, 0.15);
}
.ios {
  --f7-text-editor-toolbar-padding: 6px;
  --f7-text-editor-button-border-radius: 2px;
  --f7-text-editor-placeholder-color: rgba(0, 0, 0, 0.35);
  --f7-text-editor-toolbar-border-color: rgba(0, 0, 0, 0.25);
  --f7-text-editor-toolbar-bg-color: #fff;
  --f7-text-editor-border-color: rgba(0, 0, 0, 0.1);
  --f7-text-editor-button-text-color: #333;
}
.ios .dark,
.ios.dark {
  --f7-text-editor-placeholder-color: rgba(255, 255, 255, 0.35);
  --f7-text-editor-toolbar-bg-color: #121212;
  --f7-text-editor-toolbar-border-color: rgba(255, 255, 255, 0.1);
  --f7-text-editor-toolbar-bg-color: #202020;
  --f7-text-editor-border-color: rgba(255, 255, 255, 0.1);
  --f7-text-editor-button-text-color: #fff;
}
.md {
  --f7-text-editor-button-border-radius: 8px;
  --f7-text-editor-toolbar-padding: 8px;
}
.md,
.md .dark,
.md [class*='color-'] {
  --f7-text-editor-placeholder-color: var(--f7-md-on-surface-variant);
  --f7-text-editor-toolbar-bg-color: var(--f7-md-surface-1);
  --f7-text-editor-border-color: var(--f7-md-outline);
  --f7-text-editor-button-text-color: var(--f7-md-on-surface);
}

Examples

text-editor.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="left">
          <a class="link back">
            <i class="icon icon-back"></i>
            <span class="if-not-md">返回</span>
          </a>
        </div>
        <div class="title">富文本编辑器</div>
      </div>
    </div>
    <div class="page-content">
      <div class="block">
        <p>Framework7配备了一个触摸友好的富文本编辑器组件。它基于现代的"contenteditable" API,因此应该可以在任何地方正常工作。</p>
        <p>它带有基本的格式设置功能。但是它的功能可以很容易地扩展和定制,以适应任何需求</p>
      </div>

      <div class="block-title">默认设置</div>
      <div class="text-editor text-editor-init">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">带占位符</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text...">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">带默认值</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text...">
        <div class="text-editor-content" contenteditable>
          <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Consequatur sunt, sapiente quis eligendi
            consectetur hic asperiores assumenda quidem dolore quasi iusto tenetur commodi qui ullam sint sed alias!
            Consequatur, dolor!</p>
          <p>Provident reiciendis exercitationem reprehenderit amet repellat laborum, sequi id quam quis quo quos facere
            veniam ad libero dolorum animi. Nobis, illum culpa explicabo dolorem vitae ut dolor at reprehenderit magnam?
          </p>
          <p>Qui, animi. Dolores dicta, nobis aut expedita enim eum assumenda modi, blanditiis voluptatibus excepturi
            non pariatur. Facilis fugit facere sequi molestias nemo in, suscipit inventore consequuntur, repellat
            perferendis, voluptas odit.</p>
          <p>Tempora voluptates, doloribus architecto eligendi numquam facilis perspiciatis autem quam voluptas maxime
            ratione harum laudantium cum deleniti. In, alias deserunt voluptatibus eligendi libero nobis est unde et
            perspiciatis cumque voluptatum.</p>
          <p>Quam error doloribus qui laboriosam eligendi. Aspernatur quam pariatur perspiciatis reprehenderit atque
            dicta culpa, aut rem? Assumenda, quibusdam? Reprehenderit necessitatibus facere nemo iure maiores porro
            voluptates accusamus quibusdam. Nesciunt, assumenda?</p>
        </div>
      </div>

      <div class="block-title">指定按钮</div>
      <div class="block-header">可以自定义显示哪些按钮(命令)。</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text..."
        data-buttons='[["bold", "italic", "underline", "strikeThrough"], ["orderedList", "unorderedList"]]'>
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">自定义按钮 </div>
      <div class="block-header">可以创建自定义编辑按钮。这是一个自定义的“hr”按钮,可以添加水平线:</div>
      <div class="text-editor text-editor-custom-buttons">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">可以调整大小</div>
      <div class="block-header">编辑器将根据其内容调整大小。</div>
      <div class="text-editor text-editor-init text-editor-resizable" data-placeholder="Enter text..."
        data-buttons='["bold", "italic", "underline", "strikeThrough"]'>
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title"> 弹出模式</div>
      <div class="block-header">在这种模式下,没有工具栏按钮,但当您选择编辑器中的任何文本时,它们会以弹出窗口的形式出现。</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text..."
        data-buttons='["bold", "italic", "underline", "strikeThrough"]' data-mode="popover"
        style="--f7-text-editor-height: 150px">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">键盘工具栏模式</div>
      <div class="block-header">在这种模式下,当编辑器处于焦点状态时,将在虚拟键盘上方显示带有按钮的工具栏。它仅在iOS、Android Cordova应用程序和Android Chrome中受支持。如果不支持,它将回退到“弹出”模式。</div>
      <div class="text-editor text-editor-init" data-placeholder="Enter text..." data-mode="keyboard-toolbar"
        style="--f7-text-editor-height: 150px">
        <div class="text-editor-content" contenteditable></div>
      </div>

      <div class="block-title">作为列表的输入</div>
      <div class="block-header">文本编辑器可以与其他输入一起使用。在这个例子中,它被启用为“关于”字段的“键盘工具栏”/“弹出窗口”类型。</div>
      <div class="list list-strong-ios list-dividers-ios list-outline-ios">
        <ul>
          <li class="item-content item-input">
            <div class="item-media">
              <i class="icon demo-list-icon"></i>
            </div>
            <div class="item-inner">
              <div class="item-title item-label">名字</div>
              <div class="item-input-wrap">
                <input type="text" placeholder="Your name" />
              </div>
            </div>
          </li>
          <li class="item-content item-input">
            <div class="item-media">
              <i class="icon demo-list-icon"></i>
            </div>
            <div class="item-inner">
              <div class="item-title item-label">关于</div>
              <div class="item-input-wrap">
                <div class="text-editor text-editor-init text-editor-resizable" data-placeholder="About"
                  data-buttons='["bold", "italic", "underline", "strikeThrough"]' data-mode="popover">
                  <div class="text-editor-content" contenteditable></div>
                </div>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
<script>
  export default (props, { $f7, $el, $on }) => {
    let textEditorCustomButtons;
    $on('pageInit', () => {
      textEditorCustomButtons = $f7.textEditor.create({
        el: $el.value.find('.text-editor-custom-buttons'),
        // define custom "hr" button
        customButtons: {
          hr: {
            content: '<hr>',
            onClick(editor, buttonEl) {
              document.execCommand('insertHorizontalRule', false);
            },
          },
        },
        buttons: [["bold", "italic", "underline", "strikeThrough"], "hr"],
      });
    });
    $on('pageBeforeRemove', () => {
      textEditorCustomButtons.destroy()
    });

    return $render;
  };
</script>