diff --git a/change/react-native-windows-2dd3b1fe-b27b-4762-9038-1d1e1d3a4ab0.json b/change/react-native-windows-2dd3b1fe-b27b-4762-9038-1d1e1d3a4ab0.json
new file mode 100644
index 00000000000..2b7577436b5
--- /dev/null
+++ b/change/react-native-windows-2dd3b1fe-b27b-4762-9038-1d1e1d3a4ab0.json
@@ -0,0 +1,7 @@
+{
+ "type": "prerelease",
+ "comment": "Add hideTitleBar and hideBorder to Modal",
+ "packageName": "react-native-windows",
+ "email": "30809111+acoates-ms@users.noreply.github.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/@react-native-windows/tester/src/js/examples/Modal/ModalPresentation.windows.js b/packages/@react-native-windows/tester/src/js/examples/Modal/ModalPresentation.windows.js
index bd0dfc7383f..4015de904c5 100644
--- a/packages/@react-native-windows/tester/src/js/examples/Modal/ModalPresentation.windows.js
+++ b/packages/@react-native-windows/tester/src/js/examples/Modal/ModalPresentation.windows.js
@@ -19,7 +19,7 @@ import {RNTesterThemeContext} from '../../components/RNTesterTheme';
import RNTOption from '../../components/RNTOption';
import * as React from 'react';
import {useCallback, useContext, useState} from 'react';
-import {Modal, Platform, StyleSheet, Switch, Text, View} from 'react-native';
+import {Modal, Platform, StyleSheet, Switch, Text, TextInput, View} from 'react-native';
const animationTypes = ['slide', 'none', 'fade'] as const;
const presentationStyles = [
@@ -70,6 +70,9 @@ function ModalPresentation() {
ios: ['portrait'],
}),
transparent: false,
+ hideBorder: false, // Windows
+ hideTitleBar: false, // Windows
+ title: 'Modal Presentation', // Windows
visible: false,
});
const presentationStyle = props.presentationStyle;
@@ -190,6 +193,37 @@ function ModalPresentation() {
}
/>
+ {/* [Windows] - HideTitleBar is a Windows only prop. It is not supported on iOS or Android. */}
+
+ HideTitleBar
+
+ setProps(prev => ({...prev, hideTitleBar: enabled}))
+ }
+ />
+
+ {/* [Windows] - HideBorder is a Windows only prop. It is not supported on iOS or Android. */}
+
+ HideBorder
+
+ setProps(prev => ({...prev, hideBorder: enabled}))
+ }
+ />
+
+ {/* [Windows] - Title is a Windows only prop. It is not supported on iOS or Android. */}
+
+ Title
+
+ setProps(prev => ({...prev, title: text}))
+ }
+ />
+
{Platform.OS === 'ios' && presentationStyle !== 'overFullScreen' ? (
iOS Modal can only be transparent with 'overFullScreen' Presentation
diff --git a/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap b/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap
index 336fd341df5..b0695e2cae6 100644
--- a/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap
+++ b/packages/e2e-test-app-fabric/test/__snapshots__/snapshotPages.test.js.snap
@@ -31656,6 +31656,119 @@ exports[`snapshotAllPages Modal 1`] = `
value={false}
/>
+
+
+ HideTitleBar
+
+
+
+
+
+ HideBorder
+
+
+
+
+
+ Title
+
+
+
+#include
#include
#include
#include
@@ -112,6 +113,12 @@ struct ModalHostView : public winrt::implements::UpdateProps(view, newProps, oldProps);
}
@@ -258,6 +265,61 @@ struct ModalHostView : public winrt::implementshideTitleBar.value_or(false) && m_localProps->hideBorder.value_or(false);
+
+ auto titleBar = m_rnWindow.AppWindow().TitleBar();
+ titleBar.ResetToDefault();
+ overlappedPresenter.IsResizable(false);
+
+ overlappedPresenter.SetBorderAndTitleBar(!hideBorders, !m_localProps->hideTitleBar.value_or(false));
+
+ auto hwnd = GetWindowFromWindowId(m_rnWindow.AppWindow().Id());
+
+ if (hideBorders) {
+ const DWMNCRENDERINGPOLICY ncPolicy = DWMNCRP_DISABLED;
+ ::DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &ncPolicy, sizeof(ncPolicy));
+
+ const DWM_WINDOW_CORNER_PREFERENCE cornerPref = DWMWCP_DEFAULT;
+ ::DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPref, sizeof(cornerPref));
+
+ const COLORREF zeroColor = 0;
+ ::DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &zeroColor, sizeof(zeroColor));
+ ::DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &zeroColor, sizeof(zeroColor));
+ ::DwmSetWindowAttribute(hwnd, DWMWA_TEXT_COLOR, &zeroColor, sizeof(zeroColor));
+ } else {
+ const DWMNCRENDERINGPOLICY ncPolicy = DWMNCRP_USEWINDOWSTYLE;
+ ::DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &ncPolicy, sizeof(ncPolicy));
+
+ const DWM_WINDOW_CORNER_PREFERENCE cornerPref = DWMWCP_DEFAULT;
+ ::DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cornerPref, sizeof(cornerPref));
+
+ const COLORREF zeroColor = DWMWA_COLOR_DEFAULT;
+ ::DwmSetWindowAttribute(hwnd, DWMWA_BORDER_COLOR, &zeroColor, sizeof(zeroColor));
+ ::DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, &zeroColor, sizeof(zeroColor));
+ ::DwmSetWindowAttribute(hwnd, DWMWA_TEXT_COLOR, &zeroColor, sizeof(zeroColor));
+
+ titleBar.IconShowOptions(winrt::Microsoft::UI::Windowing::IconShowOptions::HideIconAndSystemMenu);
+ }
+ }
+
// creates a new modal window
void EnsureModalCreated(const winrt::Microsoft::ReactNative::ComponentView &view) {
if (m_popUp) {
@@ -282,22 +344,8 @@ struct ModalHostView : public winrt::implementstitle.has_value()) {
diff --git a/vnext/src-win/Libraries/Modal/Modal.d.ts b/vnext/src-win/Libraries/Modal/Modal.d.ts
index 66dc9abe8a0..f345348bae9 100644
--- a/vnext/src-win/Libraries/Modal/Modal.d.ts
+++ b/vnext/src-win/Libraries/Modal/Modal.d.ts
@@ -117,6 +117,10 @@ export interface ModalWindowsProps {
/* title for the modal, shown in the title bar */
// [Windows
title?: string | undefined;
+
+ hideTitleBar?: boolean | undefined;
+
+ hideBorder?: boolean | undefined;
// Windows]
}
diff --git a/vnext/src-win/Libraries/Modal/Modal.windows.js b/vnext/src-win/Libraries/Modal/Modal.windows.js
index 200e0239044..d02116df78b 100644
--- a/vnext/src-win/Libraries/Modal/Modal.windows.js
+++ b/vnext/src-win/Libraries/Modal/Modal.windows.js
@@ -174,6 +174,8 @@ export type ModalPropsWindows = {
* [Windows] The `title` prop sets the title of the modal window.
*/
title?: ?string,
+ hideTitleBar?: ?boolean,
+ hideBorder?: ?boolean,
};
export type ModalProps = {
@@ -352,6 +354,8 @@ class Modal extends React.Component {
onOrientationChange={this.props.onOrientationChange}
allowSwipeDismissal={this.props.allowSwipeDismissal}
testID={this.props.testID}
+ hideTitleBar={this.props.hideTitleBar} // [Windows]
+ hideBorder={this.props.hideBorder} // [Windows]
title={this.props.title}>
diff --git a/vnext/src-win/src/private/specs_DEPRECATED/components/RCTModalHostViewNativeComponent.js b/vnext/src-win/src/private/specs_DEPRECATED/components/RCTModalHostViewNativeComponent.js
index 4f1e3f8077a..b8fb6976a77 100644
--- a/vnext/src-win/src/private/specs_DEPRECATED/components/RCTModalHostViewNativeComponent.js
+++ b/vnext/src-win/src/private/specs_DEPRECATED/components/RCTModalHostViewNativeComponent.js
@@ -152,6 +152,10 @@ type RCTModalHostViewNativeProps = Readonly<{|
*/
// [Windows
title?: WithDefault,
+
+ hideTitleBar?: WithDefault,
+
+ hideBorder?: WithDefault,
// Windows]
|}>;