<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
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
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
| Event | Detail | Description |
|---|---|---|
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
| Method | Signature | Description |
|---|---|---|
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
| Slot | Description |
|---|---|
description |
Rich help text, in place of the description property. |
label |
Rich label content, in place of the label property. |
CSS shadow parts
| Part | Description |
|---|---|
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
| Property | Description |
|---|---|
--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. |