diff --git a/samples/control-replacement/README.md b/samples/control-replacement/README.md
new file mode 100644
index 00000000..683e91e3
--- /dev/null
+++ b/samples/control-replacement/README.md
@@ -0,0 +1,41 @@
+# Google Maps JavaScript Sample
+
+## control-replacement
+
+This sample demonstrates replacing default map controls with custom controls.
+
+## Setup
+
+### Before starting run:
+
+`npm i`
+
+### Run an example on a local web server
+
+`cd samples/control-replacement`
+`npm start`
+
+### Build an individual example
+
+`cd samples/control-replacement`
+`npm run build`
+
+From 'samples':
+
+`npm run build --workspace=control-replacement/`
+
+### Build all of the examples.
+
+From 'samples':
+
+`npm run build-all`
+
+### Run lint to check for problems
+
+`cd samples/control-replacement`
+`npx eslint index.ts`
+
+## Feedback
+
+For feedback related to this sample, please open a new issue on
+[GitHub](https://github.com/googlemaps-samples/js-api-samples/issues).
diff --git a/samples/control-replacement/index.html b/samples/control-replacement/index.html
new file mode 100644
index 00000000..c79c4cb6
--- /dev/null
+++ b/samples/control-replacement/index.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+ Replacing Default Controls
+
+
+
+
+
+
+
+
+
+
+ +
+ -
+
+
+
+ Map
+
+
+ Satellite
+
+
+
+
+ fullscreen
+
+
+
+
+
+
diff --git a/samples/control-replacement/index.ts b/samples/control-replacement/index.ts
new file mode 100644
index 00000000..3eb6178c
--- /dev/null
+++ b/samples/control-replacement/index.ts
@@ -0,0 +1,98 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+// [START maps_control_replacement]
+const mapElement = document.querySelector('gmp-map') as google.maps.MapElement;
+let innerMap: google.maps.Map;
+
+async function initMap() {
+ // Load the needed libraries.
+ await google.maps.importLibrary('maps');
+
+ innerMap = mapElement.innerMap;
+
+ // Disable the default controls.
+ innerMap.setOptions({
+ disableDefaultUI: true,
+ });
+
+ initZoomControl(innerMap);
+ initMapTypeControl(innerMap);
+ initFullscreenControl(innerMap);
+}
+
+function initZoomControl(map: google.maps.Map) {
+ const zoomInButton = document.querySelector(
+ '.zoom-control-in'
+ ) as HTMLButtonElement;
+ const zoomOutButton = document.querySelector(
+ '.zoom-control-out'
+ ) as HTMLButtonElement;
+
+ zoomInButton?.addEventListener('click', () => {
+ map.setZoom((map.getZoom() || 0) + 1);
+ });
+
+ zoomOutButton?.addEventListener('click', () => {
+ map.setZoom((map.getZoom() || 0) - 1);
+ });
+}
+
+async function initMapTypeControl(innerMap: google.maps.Map) {
+ const mapTypeControlDiv = document.querySelector(
+ '.maptype-control'
+ ) as HTMLElement;
+ const btnMap = document.querySelector(
+ '.maptype-control-map'
+ ) as HTMLButtonElement;
+ const btnSatellite = document.querySelector(
+ '.maptype-control-satellite'
+ ) as HTMLButtonElement;
+
+ btnMap?.addEventListener('click', () => {
+ mapTypeControlDiv.classList.add('maptype-control-is-map');
+ mapTypeControlDiv.classList.remove('maptype-control-is-satellite');
+ innerMap.setMapTypeId('roadmap');
+ });
+
+ btnSatellite?.addEventListener('click', () => {
+ mapTypeControlDiv.classList.add('maptype-control-is-satellite');
+ mapTypeControlDiv.classList.remove('maptype-control-is-map');
+ innerMap.setMapTypeId('hybrid');
+ });
+}
+
+async function initFullscreenControl(innerMap: google.maps.Map) {
+ // Get the UI elements for the fullscreen control.
+ const btnFullscreen = document.querySelector(
+ '#fullscreen-button'
+ ) as HTMLButtonElement;
+
+ btnFullscreen.addEventListener('click', () => {
+ toggleFullScreen(mapElement);
+ });
+}
+
+async function toggleFullScreen(element: google.maps.MapElement) {
+ const fullScreenIcon = document.querySelector(
+ '#fullscreen-button .material-icons'
+ ) as HTMLElement;
+
+ try {
+ if (!document.fullscreenElement) {
+ element.requestFullscreen();
+ fullScreenIcon.innerText = 'fullscreen_exit';
+ } else {
+ document.exitFullscreen();
+ fullScreenIcon.innerText = 'fullscreen';
+ }
+ } catch (error) {
+ console.error('Error toggling fullscreen:', error);
+ }
+}
+
+initMap();
+// [END maps_control_replacement]
diff --git a/samples/control-replacement/package.json b/samples/control-replacement/package.json
new file mode 100644
index 00000000..9bf3e807
--- /dev/null
+++ b/samples/control-replacement/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "@js-api-samples/control-replacement",
+ "version": "1.0.0",
+ "scripts": {
+ "build": "tsc && bash ../jsfiddle.sh control-replacement && bash ../app.sh control-replacement && bash ../docs.sh control-replacement && npm run build:vite --workspace=. && bash ../dist.sh control-replacement",
+ "test": "tsc && npm run build:vite --workspace=.",
+ "start": "tsc && vite build --base './' && vite",
+ "build:vite": "vite build --base './'",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+
+ }
+}
diff --git a/samples/control-replacement/style.css b/samples/control-replacement/style.css
new file mode 100644
index 00000000..249dce5c
--- /dev/null
+++ b/samples/control-replacement/style.css
@@ -0,0 +1,102 @@
+/**
+ * @license
+ * Copyright 2026 Google LLC. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+/* [START maps_control_replacement] */
+
+/* Optional: Makes the sample page fill the window. */
+html,
+body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+.controls {
+ background-color: white;
+ box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 4px -1px;
+ box-sizing: border-box;
+ border-radius: 2px;
+ display: flex;
+ user-select: none;
+ background-clip: padding-box;
+ overflow: hidden; /* Keeps button backgrounds inside the rounded corners */
+}
+
+.controls button {
+ border: 0;
+ background-color: white;
+ color: rgba(0, 0, 0, 0.6);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0;
+ transition: color 0.2s ease;
+}
+
+.controls button:hover {
+ color: rgba(0, 0, 0, 0.9);
+}
+
+.controls.zoom-control {
+ flex-direction: column;
+ width: 40px;
+}
+
+.controls.zoom-control button {
+ height: 40px;
+ width: 40px;
+ font-size: 24px;
+}
+
+.controls.maptype-control {
+ flex-direction: row;
+ height: 40px;
+}
+
+.controls.maptype-control button {
+ padding: 0 12px;
+ font-size: 14px;
+ font-family: Roboto, Arial, sans-serif;
+ text-transform: uppercase;
+ height: 100%;
+}
+
+.controls.maptype-control.maptype-control-is-map .maptype-control-map {
+ font-weight: 700;
+}
+
+.controls.maptype-control.maptype-control-is-satellite
+ .maptype-control-satellite {
+ font-weight: 700;
+}
+
+.controls.fullscreen-control {
+ width: 40px;
+ height: 40px;
+}
+
+.controls.fullscreen-control button {
+ background: none;
+ border: none;
+ padding: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ width: 100%;
+ height: 100%;
+}
+
+.controls.fullscreen-control {
+ width: 40px;
+ height: 40px;
+}
+
+#fullscreen-button .material-icons {
+ font-size: 28px;
+}
+
+/* [END maps_control_replacement] */
diff --git a/samples/control-replacement/tsconfig.json b/samples/control-replacement/tsconfig.json
new file mode 100644
index 00000000..139208da
--- /dev/null
+++ b/samples/control-replacement/tsconfig.json
@@ -0,0 +1,14 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "ES2022",
+ "lib": ["ES2022", "DOM"],
+ "strict": true,
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "types": ["google.maps"]
+ },
+ "include": ["./*.ts", "./types/*.d.ts"]
+}
\ No newline at end of file