Part 77: An Introduction to XML for LWC
Welcome back to the Salesforce blog series. Over the last five posts we have been working through each file type in a Lightning Web Component. In Part 72, we introduced the LWC file structure and you saw three files sitting inside every component folder — the .html template, the .js controller, and a .xml metadata file. Since then we have taken deep dives into the DOM (Part 73), HTML (Part 74), CSS (Part 75), and JavaScript (Part 76). Those four posts gave you everything you need to build a component that looks good and behaves correctly in the browser. But there is one file we have not explained yet, and without it your component will never show up anywhere in Salesforce. That file is the .js-meta.xml configuration file.
If HTML is the skeleton, CSS is the skin, and JavaScript is the brain, then the XML metadata file is the birth certificate. It tells the Salesforce platform who your component is, where it is allowed to live, and what properties administrators can configure. Without a valid XML file, your component might deploy successfully but it will be invisible — you will not find it in Lightning App Builder, you will not be able to drop it on a record page, and you will not be able to pass it design-time values. That is why understanding XML is not a nice-to-have. It is required.
In this post we will cover what XML is at a fundamental level, walk through every element and attribute you need for LWC metadata configuration, and wrap up with a comprehensive cheat sheet you can reference every time you create or modify a component.
What is XML?
XML stands for eXtensible Markup Language. It was designed in the late 1990s by the World Wide Web Consortium (W3C) as a way to store and transport structured data. If you have worked with HTML, XML will look familiar because both use tags, attributes, and a nested tree structure. The critical difference is that HTML has a fixed set of tags defined by the browser (<div>, <p>, <span>, and so on), while XML lets you define your own tags. The tag names in XML carry meaning that is specific to the application reading the file.
Here is a simple XML example that has nothing to do with Salesforce:
<book>
<title>Clean Code</title>
<author>Robert C. Martin</author>
<year>2008</year>
</book>
There is no <book> tag in HTML. But in XML, you can create any tag name you want as long as the document follows the structural rules. Those rules are straightforward:
- Every opening tag must have a matching closing tag. You cannot leave a tag unclosed.
<title>must be followed by</title>. - Tags must be properly nested. You cannot overlap them.
<a><b></a></b>is invalid.<a><b></b></a>is correct. - The document must have exactly one root element. Everything else sits inside that root.
- XML is case-sensitive.
<Book>and<book>are two different tags. - Attribute values must be quoted. You write
apiVersion="62.0", notapiVersion=62.0.
If any of these rules are violated, the XML is considered malformed and the application reading it — in our case, the Salesforce deployment process — will reject it with an error.
Why Salesforce Uses XML
Salesforce is a metadata-driven platform. Almost everything in the system — objects, fields, profiles, permission sets, flows, page layouts — is defined by metadata files. When you deploy changes through SFDX, Metadata API, or a CI/CD pipeline, you are sending XML files that describe what should exist in the org. The LWC metadata file is just one more piece of that puzzle. It follows the same pattern: a structured XML document that tells the platform how to handle your component.
The Basics of XML for LWC’s
Every Lightning Web Component includes a file named componentName.js-meta.xml. This file sits in the same folder as your .html, .js, and .css files. Let us start with the simplest valid metadata file and build up from there.
The Minimum Viable XML File
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>false</isExposed>
</LightningComponentBundle>
Let us break this down line by line.
Line 1: The XML Declaration. <?xml version="1.0" encoding="UTF-8"?> tells any application reading this file that it is an XML document using version 1.0 and UTF-8 character encoding. This line is technically optional, but you should always include it. Salesforce CLI generates it automatically when you create a component.
Line 2: The Root Element. <LightningComponentBundle> is the root element for every LWC metadata file. The xmlns attribute declares the XML namespace, which tells Salesforce that this file follows the metadata schema for Lightning components. You never change this namespace — it is the same for every LWC you will ever build.
Line 3: API Version. <apiVersion>62.0</apiVersion> specifies which version of the Salesforce API your component targets. This determines which platform features are available to your component. As a general rule, use the latest API version unless you have a specific reason to target an older one.
Line 4: Is Exposed. <isExposed>false</isExposed> controls whether your component is visible outside of its own namespace. When set to false, the component can only be used by other components in your codebase — it cannot be dragged onto a page in Lightning App Builder. When set to true, the component becomes available to administrators and page builders. This is the single most important flag in the file. If you have ever built an LWC and wondered why it did not appear in the component palette in App Builder, the answer was almost certainly that isExposed was set to false.
Making Your Component Visible with Targets
Setting isExposed to true is only half the story. You also need to tell Salesforce where the component is allowed to appear. That is what the <targets> element is for.
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>
The <targets> element contains one or more <target> child elements. Each target is a string that corresponds to a specific surface in Salesforce where the component can be placed. Here are the targets you will use most often:
lightning__RecordPage— Record detail pages. This is the most common target. It lets you place your component on the page layout for any object.lightning__AppPage— Custom app pages built in Lightning App Builder. Use this when your component is a standalone tool or dashboard widget.lightning__HomePage— The Lightning Experience home page.lightning__FlowScreen— Screen flows. This lets your component be used as a custom screen component inside a flow.lightning__UtilityBar— The utility bar at the bottom of the Lightning Experience interface.lightning__Tab— A custom Lightning tab.lightning__Inbox— The Outlook and Gmail integration panels.lightningCommunity__Page— Experience Cloud (formerly Community) pages.lightningCommunity__Default— The default Experience Cloud page context.
If you omit the <targets> element entirely, the component will not appear anywhere in Lightning App Builder even if isExposed is true. Always specify at least one target.
Adding a Master Label and Description
You can give your component a human-friendly name and description that will appear in Lightning App Builder when an administrator is browsing available components.
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Account Health Dashboard</masterLabel>
<description>Displays a visual health score for the current account based on open cases, last activity date, and contract status.</description>
<targets>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>
The <masterLabel> is what shows up as the component name in the App Builder palette. If you omit it, Salesforce will use the component’s folder name, which is usually camelCase and not very user-friendly. The <description> appears as a tooltip or subtitle. Neither of these affect the component’s behavior — they are purely for the administrator experience.
Configuring Design Attributes with targetConfigs
This is where the XML file gets really powerful. The <targetConfigs> element lets you define properties that administrators can set at design time through the Lightning App Builder interface — no code changes required. These properties map directly to @api decorated properties in your JavaScript file.
Let us say you have a component that displays a greeting message, and you want the administrator to be able to configure the greeting text and choose whether to show an icon.
Your JavaScript file would look like this:
import { LightningElement, api } from 'lwc';
export default class GreetingBanner extends LightningElement {
@api greetingText = 'Welcome!';
@api showIcon = false;
}
And your XML file would expose those properties as design attributes:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Greeting Banner</masterLabel>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__HomePage</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordPage,lightning__HomePage">
<property name="greetingText" type="String" label="Greeting Text" default="Welcome!" description="The greeting message to display." />
<property name="showIcon" type="Boolean" label="Show Icon" default="false" description="When checked, an icon will appear next to the greeting." />
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
Let us unpack the structure. The <targetConfigs> element wraps one or more <targetConfig> elements. Each <targetConfig> has a targets attribute (note: plural, and it is an attribute on the tag, not a child element) that specifies which page types this configuration applies to. Inside each <targetConfig> you define <property> elements.
Each <property> has the following attributes:
name— Must match the@apiproperty name in your JavaScript exactly, including case.type— The data type. Common types areString,Boolean,Integer,Color, andApex(for referencing an Apex class).label— The human-readable label that appears in App Builder.default— The default value if the administrator does not set one.description— Help text that appears in the App Builder panel.
Target-Specific Configurations
One of the more useful features of <targetConfigs> is the ability to define different configurations for different targets. For example, you might want your component to accept an objectApiName when it is placed on a record page but not when it is on a home page:
<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<property name="greetingText" type="String" label="Greeting Text" />
<objects>
<object>Account</object>
<object>Contact</object>
</objects>
</targetConfig>
<targetConfig targets="lightning__HomePage">
<property name="greetingText" type="String" label="Greeting Text" />
</targetConfig>
</targetConfigs>
The <objects> element inside a <targetConfig> restricts which record pages can use the component. In the example above, the component would only appear in App Builder when editing Account or Contact record pages. If you omit the <objects> element, the component is available on record pages for every object.
Flow Screen Configuration
When your component targets lightning__FlowScreen, you need to think about which properties are inputs (set by the flow), which are outputs (sent back to the flow), and which are both. You define this using the role attribute on each property:
<targetConfigs>
<targetConfig targets="lightning__FlowScreen">
<property name="accountId" type="String" label="Account ID" role="inputOnly" />
<property name="selectedOption" type="String" label="Selected Option" role="outputOnly" />
<property name="currentStep" type="Integer" label="Current Step" role="inputOutput" />
</targetConfig>
</targetConfigs>
The three possible values for role are inputOnly, outputOnly, and inputOutput. Getting these right is critical if you want your flow integration to work correctly. An inputOnly property can be set by the flow but cannot send data back. An outputOnly property can send data back to the flow but cannot receive an initial value. And inputOutput goes both ways.
Section Notes: XML for LWC’s Cheat Sheet
Here is a comprehensive reference for every element and attribute you will encounter in an LWC metadata XML file. Bookmark this section and come back to it whenever you are configuring a new component.
Root Structure
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<!-- All configuration goes here -->
</LightningComponentBundle>
Always include the XML declaration. The xmlns namespace never changes.
Core Elements
| Element | Purpose | Required | Example |
|---|---|---|---|
<apiVersion> | Salesforce API version | Yes | <apiVersion>62.0</apiVersion> |
<isExposed> | Visibility outside namespace | Yes | <isExposed>true</isExposed> |
<masterLabel> | Display name in App Builder | No | <masterLabel>My Widget</masterLabel> |
<description> | Description in App Builder | No | <description>A useful widget.</description> |
<targets> | Where the component can appear | No (but needed for App Builder) | See below |
<targetConfigs> | Design-time property configuration | No | See below |
Available Targets
| Target String | Where It Appears |
|---|---|
lightning__RecordPage | Record detail pages |
lightning__AppPage | Custom app pages |
lightning__HomePage | Lightning home page |
lightning__FlowScreen | Screen flow screens |
lightning__UtilityBar | Utility bar |
lightning__Tab | Custom tab |
lightning__Inbox | Outlook/Gmail integration |
lightningCommunity__Page | Experience Cloud pages |
lightningCommunity__Default | Experience Cloud default |
lightning__RecordAction | Record quick actions |
lightning__GlobalAction | Global quick actions |
Property Type Reference
| Type | Description | Example Value |
|---|---|---|
String | Text value | "Hello World" |
Boolean | True or false | "true" |
Integer | Whole number | "42" |
Color | Hex color code | "#FF5733" |
Date | Date value | "2025-11-15" |
DateTime | Date and time | "2025-11-15T10:30:00" |
Apex | Reference to an Apex class | "MyApexClass" |
Property Attributes
| Attribute | Purpose | Required | Notes |
|---|---|---|---|
name | Maps to @api property | Yes | Case-sensitive, must match exactly |
type | Data type | Yes | See type reference above |
label | Display label | No | Shown in App Builder UI |
default | Default value | No | Used when admin does not set a value |
description | Help text | No | Tooltip in App Builder |
role | Flow data direction | No | inputOnly, outputOnly, inputOutput |
min | Minimum value | No | For numeric types |
max | Maximum value | No | For numeric types |
placeholder | Placeholder text | No | For string inputs |
required | Whether the value must be set | No | "true" or "false" |
datasource | Picklist values | No | Comma-separated string values |
The datasource Attribute
The datasource attribute lets you present a dropdown in App Builder instead of a freeform text field:
<property name="size" type="String" label="Size" datasource="Small,Medium,Large" default="Medium" />
This gives the administrator a clean picklist of options when configuring the component. The values are comma-separated inside a single string.
Full Example: A Production-Ready XML File
Here is a complete, realistic XML file that demonstrates the most common patterns together:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Case Summary Card</masterLabel>
<description>Displays a summary of open cases for the current record with configurable display options.</description>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightning__FlowScreen</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<property name="maxCases" type="Integer" label="Maximum Cases to Display" default="5" min="1" max="50" description="The maximum number of cases shown in the summary." />
<property name="cardTitle" type="String" label="Card Title" default="Open Cases" description="The title displayed at the top of the card." />
<property name="accentColor" type="Color" label="Accent Color" default="#1B96FF" description="The color used for the card header." />
<property name="showPriority" type="Boolean" label="Show Priority Column" default="true" description="When checked, the priority column is visible." />
<property name="sortOrder" type="String" label="Sort Order" datasource="Newest First,Oldest First,Priority" default="Newest First" />
<objects>
<object>Account</object>
<object>Contact</object>
<object>Opportunity</object>
</objects>
</targetConfig>
<targetConfig targets="lightning__AppPage,lightning__HomePage">
<property name="maxCases" type="Integer" label="Maximum Cases to Display" default="10" />
<property name="cardTitle" type="String" label="Card Title" default="All Open Cases" />
</targetConfig>
<targetConfig targets="lightning__FlowScreen">
<property name="recordId" type="String" label="Record ID" role="inputOnly" description="The ID of the record to display cases for." />
<property name="selectedCaseId" type="String" label="Selected Case ID" role="outputOnly" description="The case the user selected from the list." />
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
Notice a few patterns in this example. The record page configuration has the most properties because that is where administrators need the most control. It also restricts the component to Account, Contact, and Opportunity pages using the <objects> element. The app page and home page share a simpler configuration with different defaults — the max cases default is 10 instead of 5 because those pages typically have more room. And the flow screen configuration uses role attributes to define the data flow direction.
Common Mistakes to Avoid
Here are the issues that trip up most LWC developers when working with the XML file:
- Component not showing in App Builder. Check that
isExposedistrueand that you have at least one<target>specified. - Property not appearing in the design panel. Make sure the
nameattribute on the<property>exactly matches the@apiproperty name in your JavaScript, including camelCase. - Deployment error about namespace. Verify that the
xmlnsattribute on<LightningComponentBundle>is exactlyhttp://soap.sforce.com/2006/04/metadata. A typo here will cause the deployment to fail. - Component showing on wrong pages. Review your
<targets>and<objects>elements to make sure you have not accidentally included or excluded page types. - Flow properties not mapping correctly. Double-check the
roleattribute. If a flow variable is not passing data into your component, the property might be set tooutputOnlywhen it should beinputOutput. - Default values not applying. Remember that the
defaultattribute in XML sets the App Builder default, but the initial value in your JavaScript file is what takes effect at runtime if no value is provided through the design panel. Make sure they are in sync.
Quick Reference: Minimum Files for a Deployable LWC
Every LWC needs at least these three files in its folder:
myComponent/
myComponent.html
myComponent.js
myComponent.js-meta.xml
The CSS file is optional. The XML file is not. Without it, the deployment will fail. And remember from Part 72 — the folder name, the HTML file name, the JS file name, and the XML file prefix must all match exactly.
That wraps up our tour of XML for Lightning Web Components. With this post, we have now covered every file type in the LWC bundle: HTML for structure (Part 74), CSS for styling (Part 75), JavaScript for behavior (Part 76), and XML for platform configuration (this post). You now have the foundational knowledge to build, style, program, and configure any component from scratch. In the next post, we will start putting all of these pieces together and build real components that interact with Salesforce data. See you there.