diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6859f71a..55fb6c5d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@
- Improvements to CSV/TSV highlighting, with autodetection of delimiter and support for TSV files, see #3186 (@keith-
- Improve (Sys)log error highlighting, see #3205 (@keith-hall)
- Map `ndjson` extension to JSON syntax, see #3209 (@keith-hall)
+- Map files with `csproj`, `vbproj`, `props` and `targets` extensions to XML syntax, see #3213 (@keith-hall)
## Themes
diff --git a/src/syntax_mapping/builtins/common/50-dotnet-xml.toml b/src/syntax_mapping/builtins/common/50-dotnet-xml.toml
new file mode 100644
index 00000000..1e3a860a
--- /dev/null
+++ b/src/syntax_mapping/builtins/common/50-dotnet-xml.toml
@@ -0,0 +1,2 @@
+[mappings]
+"XML" = ["*.csproj", "*.vbproj", "*.props", "*.targets"]
diff --git a/tests/syntax-tests/highlighted/XML/Directory.Build.props b/tests/syntax-tests/highlighted/XML/Directory.Build.props
new file mode 100644
index 00000000..bd4b97a0
--- /dev/null
+++ b/tests/syntax-tests/highlighted/XML/Directory.Build.props
@@ -0,0 +1,5 @@
+[38;2;255;255;255m<[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mOutDir[0m[38;2;255;255;255m>[0m[38;2;248;248;242mC:\output\$(MSBuildProjectName)[0m[38;2;255;255;255m[0m[38;2;249;38;114mOutDir[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+[38;2;255;255;255m[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
diff --git a/tests/syntax-tests/highlighted/XML/console.csproj b/tests/syntax-tests/highlighted/XML/console.csproj
new file mode 100644
index 00000000..ee49fbf0
--- /dev/null
+++ b/tests/syntax-tests/highlighted/XML/console.csproj
@@ -0,0 +1,11 @@
+[38;2;255;255;255m<[0m[38;2;249;38;114mProject[0m[38;2;248;248;242m [0m[38;2;166;226;46mSdk[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mMicrosoft.NET.Sdk[0m[38;2;230;219;116m"[0m[38;2;255;255;255m>[0m
+
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mOutputType[0m[38;2;255;255;255m>[0m[38;2;248;248;242mExe[0m[38;2;255;255;255m[0m[38;2;249;38;114mOutputType[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mTargetFramework[0m[38;2;255;255;255m>[0m[38;2;248;248;242mnet9.0[0m[38;2;255;255;255m[0m[38;2;249;38;114mTargetFramework[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mRootNamespace[0m[38;2;255;255;255m>[0m[38;2;248;248;242mSomeNamespace[0m[38;2;255;255;255m[0m[38;2;249;38;114mRootNamespace[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mImplicitUsings[0m[38;2;255;255;255m>[0m[38;2;248;248;242menable[0m[38;2;255;255;255m[0m[38;2;249;38;114mImplicitUsings[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mNullable[0m[38;2;255;255;255m>[0m[38;2;248;248;242menable[0m[38;2;255;255;255m[0m[38;2;249;38;114mNullable[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m[0m[38;2;249;38;114mPropertyGroup[0m[38;2;255;255;255m>[0m
+
+[38;2;255;255;255m[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
diff --git a/tests/syntax-tests/highlighted/XML/projectname.targets b/tests/syntax-tests/highlighted/XML/projectname.targets
new file mode 100644
index 00000000..0af85fbd
--- /dev/null
+++ b/tests/syntax-tests/highlighted/XML/projectname.targets
@@ -0,0 +1,8 @@
+[38;2;255;255;255m[0m[38;2;249;38;114mxml[0m[38;2;248;248;242m [0m[38;2;166;226;46mversion[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116m1.0[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;166;226;46mencoding[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mutf-8[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;255;255;255m?>[0m
+[38;2;255;255;255m<[0m[38;2;249;38;114mProject[0m[38;2;248;248;242m [0m[38;2;166;226;46mxmlns[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mhttp://schemas.microsoft.com/developer/msbuild/2003[0m[38;2;230;219;116m"[0m[38;2;255;255;255m>[0m
+
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mTarget[0m[38;2;248;248;242m [0m[38;2;166;226;46mName[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mTestTarget[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;166;226;46mAfterTargets[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mBuild[0m[38;2;230;219;116m"[0m[38;2;255;255;255m>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m<[0m[38;2;249;38;114mMessage[0m[38;2;248;248;242m [0m[38;2;166;226;46mImportance[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116mHigh[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;166;226;46mText[0m[38;2;248;248;242m=[0m[38;2;230;219;116m"[0m[38;2;230;219;116m-------------MHM----------------[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;255;255;255m/>[0m
+[38;2;248;248;242m [0m[38;2;255;255;255m[0m[38;2;249;38;114mTarget[0m[38;2;255;255;255m>[0m
+
+[38;2;255;255;255m[0m[38;2;249;38;114mProject[0m[38;2;255;255;255m>[0m
diff --git a/tests/syntax-tests/source/XML/Directory.Build.props b/tests/syntax-tests/source/XML/Directory.Build.props
new file mode 100644
index 00000000..95da98cf
--- /dev/null
+++ b/tests/syntax-tests/source/XML/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+ C:\output\$(MSBuildProjectName)
+
+
diff --git a/tests/syntax-tests/source/XML/console.csproj b/tests/syntax-tests/source/XML/console.csproj
new file mode 100644
index 00000000..61dd6821
--- /dev/null
+++ b/tests/syntax-tests/source/XML/console.csproj
@@ -0,0 +1,11 @@
+
+
+
+ Exe
+ net9.0
+ SomeNamespace
+ enable
+ enable
+
+
+
diff --git a/tests/syntax-tests/source/XML/projectname.targets b/tests/syntax-tests/source/XML/projectname.targets
new file mode 100644
index 00000000..fc597ed2
--- /dev/null
+++ b/tests/syntax-tests/source/XML/projectname.targets
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+