Skip to content

AisEditor ​

AisEditor provides a rich-text editor that allows users to compose HTML text. The text may include paragraphs, lists, and various styles such as bold and italic. Common keyboard shortcuts work as expected including undo and redo. It is built using the TipTap library which is built on top of ProseMirror.

This initial version of AisEditor is derived from a single application. We are interested in feedback from AIS developers to help us better understand the features needed to support a wide-range of applications. If you have feedback, please comment on the GitLab issue

Props ​

v-model ​

Use the v-model directive to bind to an editor's value. v-model uses the modelValue prop under the covers. See Vue's documentation for details.

placeholder ​

placeholder sets the text that appears when no value is set.

height ​

height sets the height of the editing surface (i.e. does not include the toolbar). It expects a Tailwind height class. The default value is h-fit, which allows the editor to grow between the minHeight and maxHeight based on the editor's content. If you want the editor to maintain a static height use a specific height class. h-56 (14rem) is a good starting point. You can use Tailwind's arbitrary value if the default options don't work (e.g. h-[33vh]).

minHeight ​

minHeight takes a Tailwind class to specify the minimum height of the editor. It's useful to think of this as the height of an empty editor. The default value is min-h-[2.55rem], which is roughly 1 line of text at the base font size.

maxHeight ​

maxHeight takes a Tailwind class to specify the maximum height of the editor. The default value is max-h-[50vh], which limits the editor to half the viewport height. In general it is a good idea to not let the editor grow beyond the bounds of the viewport.

disabled ​

Use the boolean disabled prop to disable an AisEditor. You can use disabled by itself or :disabled="true".

invalid ​

Use the boolean invalid prop to disable an AisEditor. You can use invalid by itself or :invalid="true".

size ​

AisEditor accepts the following sizes, sm, md, lg, and xl. Currently size corresponds directly to font size. Medium (md) is the default value.

rounded ​

The rounded prop controls the border radius of the editor. The accepted values are: true, false, sm, rounded, md, lg, and xl. The default value is false.

Events ​

update:modelValue ​

AisEditor uses Vue's standard v-model configuration. As a result, it will fire the @update:modelValue event whenever the editor's value changes. Typically, v-model should be preferred, but binding the event directly may be useful in special circumstances. See Vue's documentation for details.

Methods ​

focus() ​

AisEditor exposes a focus() method to programmatically focus the button element. The method can be invoked through a template ref specified on an AisEditor component.

Pasting ​

Content pasted into AisEditor is cleaned up before it enters the document. Text copied from Google Docs, Word Online, and desktop Word carries heavy vendor markup — inline styles, bookkeeping attributes, and formatting expressed in ways the editor doesn't use. The paste pipeline normalizes that markup so what lands in your v-model is the same clean, semantic HTML the editor produces when users type.

What is preserved:

  • Paragraphs and headings (headings only when the headings feature is enabled; otherwise they flatten to paragraphs, matching typed behavior)
  • Bullet and numbered lists, including nesting and restarted numbering (start)
  • Lists pasted from desktop Word, which puts no list markup on the clipboard at all — its list items arrive as ordinary paragraphs with the bullet or number as literal text. They are rebuilt into real lists, so they renumber, indent, and toggle with the toolbar the same way a list pasted from Word Online does.
  • Bold, italic, strikethrough, subscript, and superscript — including formatting that sources like Google Docs express as inline styles rather than tags
  • Links to http(s), mailto, and tel URLs, and relative URLs

What is removed:

  • All styling: style and class attributes, fonts, colors, sizes, and alignment
  • All other attributes (id, dir, aria-*, vendor bookkeeping) except href on links and start on numbered lists
  • Blank lines and empty paragraphs — consecutive paragraphs stay separated by normal paragraph spacing
  • Underline, which the editor does not support
  • Links with unsafe URL schemes (e.g. javascript:) — the link text is kept, the href is dropped

Note: as of the fix for issue #599, attribute stripping is broader than in earlier releases (previously only class and style were removed). If your application relied on other attributes surviving a paste, that behavior has changed.

Headings (experimental) ​

Enable Headings ​

HTML headings in the editor (<h1>–<h6>) is currently an opt-in feature while we validate it across applications. Headings remain off by default. It is enabled via Vue's provide/inject mechanism using the AIS_EDITOR_HEADINGS key rather than a prop. As such, the public API and default behavior is unchanged from version 0.4.23.

When enabled, through an ancestor component providing the flag, every AisEditor beneath it registers the heading extension and shows the heading dropdown in the toolbar. This allows users to compose with headings and load richer HTML content. Headings will no longer be flattened to paragraph tags.

js
import { provide } from 'vue'
import { AIS_EDITOR_HEADINGS } from '@ais-public/ais-components'

provide(AIS_EDITOR_HEADINGS, true)

Styles ​

Note: The component does not provide CSS styles for headings. AisEditor's contract is semantic HTML (<h2>…</h2>), not presentation. The headings are styled by the application's style sheet. It may not be obvious to users that how the headings look in the editor will not automatically match how they will look when displayed elsewhere.

We have created experimental styles that are roughly brand-based. Enable them by adding the ais-prose class to the editor component. Likewise, add ais-prose again where the content is displayed to match those styles. I would like to hear feedback from developers before we lock in these expectations.

Style headings inside the editor by scoping your CSS with .ais-editor, e.g. .ais-editor h1 { ... }. For an example, see how the first heading below is italicized.

Example ​

<h2>Introduction</h2><p>AisEditor can preserve heading tags when the feature is enabled.</p><h3>Details</h3><ul><li>Use the toolbar style dropdown to apply Heading 1&ndash;6.</li><li>Existing headings in loaded or pasted HTML are kept intact.</li></ul>

Nested lists (experimental) ​

Bullet and numbered lists have always been supported, and lists can already be nested by pressing Tab to indent a list item and Shift+Tab to outdent it. Nested lists also round-trip correctly — they are preserved when HTML is loaded, pasted, or emitted. This behavior is unchanged and on by default.

Enable the toolbar controls ​

Because keyboard-only nesting isn't very discoverable, this feature adds Indent and Outdent toolbar buttons. They are currently an opt-in feature while we validate the toolbar across applications, so they remain hidden by default. Like the headings feature, they are enabled via Vue's provide/inject mechanism using the AIS_EDITOR_NESTED_LISTS key rather than a prop, so the public API and default toolbar are unchanged from version 0.4.24.

When enabled, through an ancestor component providing the flag, every AisEditor beneath it shows the Indent / Outdent buttons in the list section of the toolbar. The buttons apply to the list item at the cursor and are equivalent to the Tab / Shift+Tab shortcuts.

js
import { provide } from 'vue'
import { AIS_EDITOR_NESTED_LISTS } from '@ais-public/ais-components'

provide(AIS_EDITOR_NESTED_LISTS, true)

Styles ​

The component indents nested lists and varies the bullet marker by depth (disc → circle → square) so the structure reads clearly while editing. As with the rest of AisEditor, this is baseline structural styling — the optional .ais-prose class layers on the experimental, roughly brand-based styles, and should also be applied where the content is displayed so the two match. See the Headings section for more on the .ais-prose opt-in.

Example ​

<ul><li><p>Fruit</p><ul><li><p>Apples</p></li><li><p>Berries</p><ul><li><p>Strawberries</p></li><li><p>Blueberries</p></li></ul></li></ul></li><li><p>Vegetables</p></li></ul>