v3.0.0

<bmx-xml-editor>

XML for integration and configuration work, edited as text (the library's code editor with XML colouring, folding and completion) or as a tree (expand, edit values and attributes in place, rename, add, move, duplicate, comment out and delete), and compared with another version.

27 properties · 5 events · 17 methods · 11 parts

Example

Checking...

Show markup
<bmx-xml-editor id="ex-xe" label="Purchase order" name="order" compare-label="As sent on Monday" description="Checked against the order schema as you edit. In the second line, type < after its Item to see what can follow, or try a quantity of 0."></bmx-xml-editor>
<p class="note" id="ex-xe-out" role="status" style="margin: 12px 0 0">Checking...</p>

<script type="module">
  await customElements.whenDefined('bmx-xml-editor');
  const editor = document.getElementById('ex-xe');
  const out = document.getElementById('ex-xe-out');

  // A made-up supplier's order schema, in two documents: the shared types are imported from the second.
  const commonXsd = `<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="urn:example:common" xmlns="urn:example:common" elementFormDefault="qualified">
  <xs:simpleType name="Money">
    <xs:annotation><xs:documentation>An amount with at most two decimal places, zero or more.</xs:documentation></xs:annotation>
    <xs:restriction base="xs:decimal"><xs:minInclusive value="0"/><xs:fractionDigits value="2"/></xs:restriction>
  </xs:simpleType>
  <xs:simpleType name="Currency">
    <xs:restriction base="xs:token"><xs:enumeration value="GBP"/><xs:enumeration value="EUR"/><xs:enumeration value="USD"/></xs:restriction>
  </xs:simpleType>
  <xs:complexType name="Party">
    <xs:sequence>
      <xs:element name="Name" type="xs:string"/>
      <xs:element name="Street" type="xs:string" maxOccurs="2"/>
      <xs:element name="City" type="xs:string"/>
      <xs:element name="Postcode"><xs:simpleType><xs:restriction base="xs:token"><xs:pattern value="[A-Z]{1,2}[0-9][A-Z0-9]? [0-9][A-Z]{2}"/></xs:restriction></xs:simpleType></xs:element>
    </xs:sequence>
    <xs:attribute name="vatNumber" type="xs:token"/>
  </xs:complexType>
</xs:schema>`;

  const orderXsd = `<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="urn:example:order" xmlns="urn:example:order" xmlns:c="urn:example:common"
    elementFormDefault="qualified">
  <xs:import namespace="urn:example:common" schemaLocation="common.xsd"/>
  <xs:element name="PurchaseOrder">
    <xs:annotation><xs:documentation>One order from a buyer to a supplier.</xs:documentation></xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="OrderNumber"><xs:simpleType><xs:restriction base="xs:token"><xs:pattern value="PO-[0-9]{6}"/></xs:restriction></xs:simpleType></xs:element>
        <xs:element name="IssueDate" type="xs:date"/>
        <xs:element name="DeliverBy" type="xs:date" minOccurs="0"/>
        <xs:element name="Buyer" type="c:Party"/>
        <xs:element name="Supplier" type="c:Party"/>
        <xs:element name="Line" type="LineType" maxOccurs="unbounded"/>
        <xs:element name="Note" type="xs:string" minOccurs="0"/>
        <xs:element name="Total" type="c:Money"/>
      </xs:sequence>
      <xs:attribute name="currency" type="c:Currency" use="required"/>
      <xs:attribute name="status" default="draft">
        <xs:simpleType><xs:restriction base="xs:token"><xs:enumeration value="draft"/><xs:enumeration value="sent"/><xs:enumeration value="accepted"/></xs:restriction></xs:simpleType>
      </xs:attribute>
    </xs:complexType>
    <xs:unique name="lineNumbers"><xs:selector xpath="Line"/><xs:field xpath="@no"/></xs:unique>
  </xs:element>
  <xs:complexType name="LineType">
    <xs:sequence>
      <xs:element name="Item" type="xs:token"/>
      <xs:element name="Description" type="xs:string" minOccurs="0"/>
      <xs:element name="Quantity">
        <xs:complexType><xs:simpleContent><xs:extension base="xs:positiveInteger">
          <xs:attribute name="unit" use="required"><xs:simpleType><xs:restriction base="xs:token"><xs:enumeration value="EA"/><xs:enumeration value="BOX"/><xs:enumeration value="KG"/></xs:restriction></xs:simpleType></xs:attribute>
        </xs:extension></xs:simpleContent></xs:complexType>
      </xs:element>
      <xs:element name="UnitPrice" type="c:Money"/>
    </xs:sequence>
    <xs:attribute name="no" type="xs:positiveInteger" use="required"/>
  </xs:complexType>
</xs:schema>`;

  const sent = `<?xml version="1.0" encoding="UTF-8"?>
<PurchaseOrder xmlns="urn:example:order" xmlns:c="urn:example:common" currency="GBP" status="sent">
  <OrderNumber>PO-004217</OrderNumber>
  <IssueDate>2026-10-19</IssueDate>
  <DeliverBy>2026-10-30</DeliverBy>
  <Buyer vatNumber="GB123456789">
    <c:Name>Harbour Lane Studio</c:Name>
    <c:Street>14 Quay Street</c:Street>
    <c:City>Bristol</c:City>
    <c:Postcode>BS1 4DB</c:Postcode>
  </Buyer>
  <Supplier>
    <c:Name>Fernhill Paper Co.</c:Name>
    <c:Street>Unit 3, Mill Road</c:Street>
    <c:City>Leeds</c:City>
    <c:Postcode>LS9 7QD</c:Postcode>
  </Supplier>
  <!-- Prices as agreed on the October price list. -->
  <Line no="1">
    <Item>A4-120-WHITE</Item>
    <Description>A4 paper, 120 gsm, white</Description>
    <Quantity unit="BOX">6</Quantity>
    <UnitPrice>18.40</UnitPrice>
  </Line>
  <Line no="2">
    <Item>ENV-C5-KRAFT</Item>
    <Quantity unit="BOX">2</Quantity>
    <UnitPrice>11.25</UnitPrice>
  </Line>
  <Line no="3">
    <Item>TAPE-PAPER-48</Item>
    <Description>Paper tape, 48 mm</Description>
    <Quantity unit="EA">12</Quantity>
    <UnitPrice>2.10</UnitPrice>
  </Line>
  <Total>158.10</Total>
</PurchaseOrder>
`;

  editor.schema = [
    { text: orderXsd, location: 'order.xsd' },
    { text: commonXsd, location: 'common.xsd' },
  ];
  // The order as it is now: the buyer has raised the paper to eight boxes and added a note.
  editor.value = sent
    .replace('<Quantity unit="BOX">6</Quantity>', '<Quantity unit="BOX">8</Quantity>')
    .replace('  <Total>158.10</Total>', '  <Note>Please deliver to the side entrance.</Note>\n  <Total>194.90</Total>');
  editor.compareWith = sent;
  editor.xpath = '//Line[Quantity > 5]/Item';

  const report = ({ wellFormed, valid, problems }) => {
    if (!wellFormed) out.textContent = `Not well-formed: ${problems[0]?.message ?? ''}`;
    else if (!valid) out.textContent = `${problems.length} problem${problems.length === 1 ? '' : 's'} against the schema: ${problems[0].message}`;
    else out.textContent = 'Valid against the order schema - ready to send.';
  };
  editor.addEventListener('bmxValidate', event => report(event.detail));
  await editor.validate();
</script>
<bmx-xml-editor label="Purchase order" name="order"></bmx-xml-editor>
<script>
  editor.schema = [{ text: orderXsd, location: 'order.xsd' }];
  editor.value = orderXml;
</script>

The document is checked as it is edited: every well-formedness mistake is underlined where it is, and with a schema (schema, or schema-src for the page's own copies), against XML Schema 1.0 - each broken rule on the element or attribute that breaks it, in plain words, listed in a problems panel that takes you to each. Completion offers the elements the schema allows at the caret, in order, the attributes an element can still take, and enumerated values; the tree offers the same when adding.

An XPath 1.0 bar finds nodes (the document's own prefixes work, and names without a prefix mean the root's default namespace), highlights them in the text and the tree, and steps through them. Format, minify, and Canonical XML or Exclusive XML Canonicalization are a click away. Edits made in the tree change only the characters they must, so the rest of the file keeps its layout. Every edit can be refused (cancel bmxEdit) and undone.

Nothing leaves the page: schemas are read from what you give, and xs:import or xs:include are resolved among those documents (or, with schema-src, fetched beside it from the same server). In a form, name receives the text; require-valid keeps the form from submitting until the document is valid.

Tree keyboard: arrows move and open/close, Home/End, Page Up/Down, Enter edits a value (or opens an element), F2 renames, Delete deletes, Insert adds, Alt+Up/Down move, Ctrl+D duplicates, Ctrl+C copies the node's XML, Shift+F10 or the context-menu key opens actions.

Properties

PropertyAttributeTypeDefaultDescription
checking checking boolean true Check the document as it changes (well-formedness always; the schema when there is one).
compareLabel compare-label string — What the original side of the comparison is called.
compareWith compare-with string — Another version of the document, for the Compare view.
description description string — Help text below the editor.
disabled disabled boolean false Disable the editor.
errorText error-text string — An error supplied by the page.
expandDepth expand-depth number 3 How many levels of the tree start open.
hideLabel hide-label boolean false Hide the label visually while keeping it as the accessible name.
hideStatus hide-status boolean false Hide the status bar.
hideToolbar hide-toolbar boolean false Hide the toolbar.
indent indent number | 'tab' — Spaces per level when formatting, or tab. Default: what the document uses.
label label string — The field's label: names the whole control.
lineWidth line-width number 120 Lines longer than this put their attributes one a line when formatting (0 never).
name name string — The field's name in a form: it receives the text.
namespaces namespaces Record<string, string> | string — Prefixes for XPath, as an object or JSON ({"inv": "urn:example:invoice"}). The document's own prefixes are added.
readonly readonly boolean false Allow reading, searching and copying, but not changing.
requireValid require-valid boolean false Keep the form from submitting until the document is well-formed and valid.
schema schema BmxXmlEditorSchema — The schema: XSD text, { text, location }, a list of them (includes and imports are found among them by location), or one read with compileXmlSchema.
schemaMessages schema-messages Record<string, string> | string — Schema messages in place of the English ones, by problem code (missing-element, bad-value, ...), as an object or JSON.
schemaSrc schema-src string — Addresses of schema documents to fetch (space or comma separated); xs:include and xs:import beside them are fetched too.
src src string — An address to load the document from (the page's own server).
strings strings Partial<BmxXmlEditorStrings> | string — Words to show instead of the English ones, as an object or JSON.
value value string '' The XML text. Two-way.
view view BmxXmlEditorView 'text' The view shown. Two-way.
views views BmxXmlEditorView[] | string — The views offered, as an array, JSON or a comma list. Default: text and tree, and compare when compare-with is set.
xpath xpath string '' The XPath expression in the XPath bar. Two-way. Setting it opens the bar.
xpathDefaultNamespace xpath-default-namespace string 'auto' What a name without a prefix means in XPath: auto (the root element's default namespace), none (no namespace, as XPath 1.0 says), or a namespace.

Events

EventDetailDescription
bmxChange BmxXmlChangeDetail Fired after the text changes.
bmxEdit BmxXmlEditDetail Fired before an edit made with the tree or a command. Cancel it to refuse the edit.
bmxSelect BmxXmlSelectDetail Fired when the selected node changes (in the tree, or the node at the caret).
bmxValidate BmxXmlValidateDetail Fired after each check of the document.
bmxXpath BmxXmlXPathDetail Fired when the XPath expression has been run.

Methods

MethodSignatureDescription
collapseAll collapseAll() => Promise<void>
evaluate evaluate(expression: string) => Promise<BmxXmlXPathDetail> Run an XPath expression (without changing the XPath bar).
expandAll expandAll(depth?: number) => Promise<void>
format format() => Promise<boolean> Lay the document out, indented. Returns whether it changed (false when it is not well-formed).
getCanonical getCanonical(options?: { exclusive?: boolean; comments?: boolean; }) => Promise<string | null> The document in Canonical XML 1.0 (or exclusive: Exclusive XML Canonicalization), without changing it. Null when it is not well-formed.
getProblems getProblems() => Promise<BmxXmlProblem[]> The problems found by the last check.
getSelection getSelection() => Promise<BmxXmlSelectDetail | null> The selected node (in the tree, or at the caret).
getValue getValue() => Promise<string> The text now (including typing not yet reported).
goTo goTo(line: number, column?: number) => Promise<void> Put the caret at a line and column (from 1), in the text view.
minify minify() => Promise<boolean> Put the document on one line. Returns whether it changed.
redo redo() => Promise<boolean>
save save(fileName?: string) => Promise<void> Download the document as a file (default name document.xml).
select select(path: string) => Promise<boolean> Select a node by its path (/Invoice/Line[2]) or the first node an XPath expression finds, and show it. Returns whether one was found.
setFocus setFocus() => Promise<void>
setValue setValue(text: string, options?: { keepHistory?: boolean; }) => Promise<void> Replace the whole text. With keepHistory, it can be undone.
undo undo() => Promise<boolean>
validate validate() => Promise<BmxXmlProblem[]> Check now: well-formedness and, with a schema, validity. Returns every problem.

Slots

SlotDescription
description Rich help text, in place of the description property.
label Rich label content, in place of the label property.

CSS shadow parts

PartDescription
description The help text under the field.
label The label element.
menu The actions menu.
name An element's or attribute's name in a row.
problems The problems panel.
row A tree row; also row-selected, row-problem, row-match.
status The bar under the views.
toolbar The bar of views and commands.
tree The tree.
value A value in a row.
xpath The XPath bar and its results.

CSS custom properties

PropertyDescription
--bmx-xml-editor-attribute-color Attribute names in the tree.
--bmx-xml-editor-background The views' background.
--bmx-xml-editor-height The height of the views' scrolling area.
--bmx-xml-editor-indent How far each level of the tree is indented.
--bmx-xml-editor-label-font-size The label's font size.
--bmx-xml-editor-radius Corner radius of the frame.
--bmx-xml-editor-results-height The most the XPath results list takes before it scrolls.
--bmx-xml-editor-row-height The height of one tree row.
--bmx-xml-editor-selected-background The selected row and XPath result.
--bmx-xml-editor-support-font-size Font size of the description and error message.
--bmx-xml-editor-tag-color Element names in the tree.
--bmx-xml-editor-text-color Text content.
--bmx-xml-editor-value-color Attribute values.