Repository: tauri-apps/tauri (language: rust)

Issue:
[bug][linux][v2] App window is not properly focused on creation since v2
### Describe the bug

Hi, I upgraded from v1 to the latest v2 RC, and the window is not focused anymore on creation, even though I have set `focus: true` in the `tauri.conf.json`

I also added those permissions to the `capabilities/main.json`:

```json
    "core:window:default",
    "core:window:allow-set-focus",
```

Note that tauri v2 docs still mention `focus` in the window config: https://v2.tauri.app/reference/config/#windowconfig

### Reproduction

Relevant project where I use tauri: https://github.com/vemonet/EmojiMart

Minimal repro:
1. Initialize new tauri project for solidjs: `npm create tauri-app@latest -- --rc`
2. Enable focus in `tauri.conf.json`

```json
{
  "app": {
    "windows": [
      {
        "title": "new-tauri-app",
        "width": 800,
        "height": 600,
        "focus": true
      }
    ],
}
```

3. Enable permissions to close window in `src-tauri/capabilities/default.json`

```json
{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": ["main"],
  "permissions": [
    "shell:allow-open",
    "core:window:default",
    "core:window:allow-close",
    "core:window:allow-set-focus"
  ]
}
```

4. Add code to close window when hitting esc key (to find out if the window is focused or not) in `src/App.tsx`
```ts
import { getCurrentWindow } from "@tauri-apps/api/window";

function App() {
  // ...
  onMount(() => {
    document.addEventListener('keypress', (event: any) => {
      if (event.code === 'Escape') getCurrentWindow().close()
    })
  })
  // ...
}
```

5. Start the app in dev with `npm run tauri dev`
6. Try to hit esc after the window pop (without clicking on the window or hitting tab): the window does not close, because it is not focused properly. If you click on the window or hit tab then the window is focused and esc will properly close hit.

### Expected behavior

When the tauri app window pops it should be fully focus without the need to click on it or hit tab (which was the behavior in tauri v1)

### Full `tauri info` output

```text
[✔] Environment
    - OS: Ubuntu 22.04 X64
    ✔ webkit2gtk-4.1: 2.44.2
    ✔ rsvg2: 2.52.5
    ✔ rustc: 1.80.1 (3f5fd8dd4 2024-08-06)
    ✔ cargo: 1.80.1 (376290515 2024-07-16)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-x86_64-unknown-linux-gnu (default)
    - node: 20.17.0
    - yarn: 1.22.22
    - npm: 10.8.2

[-] Packages
    - tauri [RUST]: 2.0.0-rc.6
    - tauri-build [RUST]: 2.0.0-rc.6
    - wry [RUST]: 0.42.0
    - tao [RUST]: 0.29.1
    - @tauri-apps/api [NPM]: 2.0.0-rc.3
    - @tauri-apps/cli [NPM]: 2.0.0-rc.7

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../build
    - devUrl: http://localhost:5173/
    - framework: Svelte
    - bundler: Vite
```


### Stack trace

_No response_

### Additional context

_No response_


Discussion / hints:
I can reproduce this bug. Actually, the App is focused. So, for vanilla JS template, I performed the following steps:

1. Add `greet();` in JS file, inside the `window.addEventListener("DOMContentLoaded")` like this, so that `greet()` is called as soon as DOM is loaded. Also, add `Escape` keypress event.

```js
window.addEventListener("DOMContentLoaded", () => {
  greetInputEl = document.querySelector("#greet-input");
  greetMsgEl = document.querySelector("#greet-msg");
  greet();
});

document.addEventListener('keypress', (event) =>  {
  if (event.code === 'Escape'){
    greet()
  }
})
```

2. Edit `greet()` in `main.rs` to print `is_focused()` for each `webview_window()`.

```rust
#[tauri::command]
fn greet(app: tauri::AppHandle ,name: &str) -> String {
    for i in app.webview_windows() {
        println!("{:?}", i.1.is_focused());
    }

    format!("Hello, {}! You've been greeted from Rust!", name)
}
```


**Result:** It printed `Ok(true)`, and App is indeed in focus. However, nothing happens on pressing `Escape`, till I click inside the window.
Interesting, so using `app.webview_windows()` show that Tauri **thinks** the app is focus when it is actually not... So the whole API about focused window is broken (at least on x11)

I don't trust what the APIs says, it is probably wrong if there is a problem

The fact is: if the window view was really focused on popup then hitting `esc` would close the app wihout the need to close the window.

The problem is still there after upgrading to tauri `2.0.1`, this is quite annoying because we are losing basic features by upgrading. Any chances this behavior get fixed?

Fix patch:
diff --git a/.changes/webview-focus-apis.md b/.changes/webview-focus-apis.md
new file mode 100644
index 000000000000..2d478fede8cd
--- /dev/null
+++ b/.changes/webview-focus-apis.md
@@ -0,0 +1,5 @@
+---
+"tauri": "patch:feat"
+---
+
+Add `WebviewBuilder::focused` method to choose whether to focus webview or not on creation.
diff --git a/.changes/webview-window-focused.md b/.changes/webview-window-focused.md
new file mode 100644
index 000000000000..b95b4cf42a74
--- /dev/null
+++ b/.changes/webview-window-focused.md
@@ -0,0 +1,7 @@
+---
+"tauri": "patch:bug"
+"tauri-runtime": "patch:bug"
+"tauri-runtime-wry": "patch:bug"
+---
+
+Fix webview not focused by default.
diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json
index a05ba79935ed..047c4a7393e0 100644
--- a/crates/tauri-cli/config.schema.json
+++ b/crates/tauri-cli/config.schema.json
@@ -1104,7 +1104,7 @@
       ]
     },
     "Capability": {
-      "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n   \"identifier\": \"main-user-files-write\",\n   \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n   \"windows\": [\n     \"main\"\n   ],\n  \"permissions\": [\n   \"core:default\",\n   \"dialog:open\",\n   {\n     \"identifier\": \"fs:allow-write-text-file\",\n     \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n   },\n  ],\n  \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
+      "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n   \"identifier\": \"main-user-files-write\",\n   \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n   \"windows\": [\n     \"main\"\n   ],\n   \"permissions\": [\n     \"core:default\",\n     \"dialog:open\",\n     {\n       \"identifier\": \"fs:allow-write-text-file\",\n       \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n     },\n   ],\n   \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
       "type": "object",
       "required": [
         "identifier",
@@ -1151,7 +1151,7 @@
           }
         },
         "permissions": {
-          "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n  \"core:default\",\n  \"shell:allow-open\",\n  \"dialog:open\",\n  {\n    \"identifier\": \"fs:allow-write-text-file\",\n    \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n  }\n ```",
+          "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n   \"core:default\",\n   \"shell:allow-open\",\n   \"dialog:open\",\n   {\n     \"identifier\": \"fs:allow-write-text-file\",\n     \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n   }\n ]\n ```",
           "type": "array",
           "items": {
             "$ref": "#/definitions/PermissionEntry"
diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs
index 4dd17d494910..0e2f23386f46 100644
--- a/crates/tauri-runtime-wry/src/lib.rs
+++ b/crates/tauri-runtime-wry/src/lib.rs
@@ -789,6 +789,7 @@ impl WindowBuilder for WindowBuilderWrapper {
       window = window
         .title(config.title.to_string())
         .inner_size(config.width, config.height)
+        .focused(config.focus)
         .visible(config.visible)
         .resizable(config.resizable)
         .fullscreen(config.fullscreen)
@@ -4017,7 +4018,7 @@ fn create_webview<T: UserEvent>(
 
   let mut webview_builder = WebViewBuilder::with_web_context(&mut web_context.inner)
     .with_id(&label)
-    .with_focused(window.is_focused())
+    .with_focused(webview_attributes.focus)
     .with_url(&url)
     .with_transparent(webview_attributes.transparent)
     .with_accept_first_mouse(webview_attributes.accept_first_mouse)
diff --git a/crates/tauri-runtime/src/webview.rs b/crates/tauri-runtime/src/webview.rs
index 4c4c83e3ea8a..651aaec5eac3 100644
--- a/crates/tauri-runtime/src/webview.rs
+++ b/crates/tauri-runtime/src/webview.rs
@@ -204,6 +204,7 @@ pub struct WebviewAttributes {
   pub window_effects: Option<WindowEffectsConfig>,
   pub incognito: bool,
   pub transparent: bool,
+  pub focus: bool,
   pub bounds: Option<Rect>,
   pub auto_resize: bool,
   pub proxy_url: Option<Url>,
@@ -213,8 +214,11 @@ pub struct WebviewAttributes {
 
 impl From<&WindowConfig> for WebviewAttributes {
   fn from(config: &WindowConfig) -> Self {
-    let mut builder = Self::new(config.url.clone());
-    builder = builder.incognito(config.incognito);
+    let mut builder = Self::new(config.url.clone())
+      .incognito(config.incognito)
+      .focused(config.focus)
+      .zoom_hotkeys_enabled(config.zoom_hotkeys_enabled)
+      .browser_extensions_enabled(config.browser_extensions_enabled);
     #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))]
     {
       builder = builder.transparent(config.transparent);
@@ -235,8 +239,6 @@ impl From<&WindowConfig> for WebviewAttributes {
     if let Some(url) = &config.proxy_url {
       builder = builder.proxy_url(url.to_owned());
     }
-    builder = builder.zoom_hotkeys_enabled(config.zoom_hotkeys_enabled);
-    builder = builder.browser_extensions_enabled(config.browser_extensions_enabled);
     builder
   }
 }
@@ -256,6 +258,7 @@ impl WebviewAttributes {
       window_effects: None,
       incognito: false,
       transparent: false,
+      focus: true,
       bounds: None,
       auto_resize: false,
       proxy_url: None,
@@ -338,6 +341,13 @@ impl WebviewAttributes {
     self
   }
 
+  /// Whether the webview should be focused or not.
+  #[must_use]
+  pub fn focused(mut self, focus: bool) -> Self {
+    self.focus = focus;
+    self
+  }
+
   /// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
   #[must_use]
   pub fn auto_resize(mut self) -> Self {
diff --git a/crates/tauri-schema-generator/schemas/capability.schema.json b/crates/tauri-schema-generator/schemas/capability.schema.json
index 80df9a6893f8..0c9462c500aa 100644
--- a/crates/tauri-schema-generator/schemas/capability.schema.json
+++ b/crates/tauri-schema-generator/schemas/capability.schema.json
@@ -1,7 +1,7 @@
 {
   "$schema": "http://json-schema.org/draft-07/schema#",
   "title": "Capability",
-  "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n   \"identifier\": \"main-user-files-write\",\n   \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n   \"windows\": [\n     \"main\"\n   ],\n  \"permissions\": [\n   \"core:default\",\n   \"dialog:open\",\n   {\n     \"identifier\": \"fs:allow-write-text-file\",\n     \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n   },\n  ],\n  \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
+  "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n   \"identifier\": \"main-user-files-write\",\n   \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n   \"windows\": [\n     \"main\"\n   ],\n   \"permissions\": [\n     \"core:default\",\n     \"dialog:open\",\n     {\n       \"identifier\": \"fs:allow-write-text-file\",\n       \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n     },\n   ],\n   \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
   "type": "object",
   "required": [
     "identifier",
@@ -48,7 +48,7 @@
       }
     },
     "permissions": {
-      "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n  \"core:default\",\n  \"shell:allow-open\",\n  \"dialog:open\",\n  {\n    \"identifier\": \"fs:allow-write-text-file\",\n    \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n  }\n ```",
+      "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n   \"core:default\",\n   \"shell:allow-open\",\n   \"dialog:open\",\n   {\n     \"identifier\": \"fs:allow-write-text-file\",\n     \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n   }\n ]\n ```",
       "type": "array",
       "items": {
         "$ref": "#/definitions/PermissionEntry"
diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json
index a05ba79935ed..047c4a7393e0 100644
--- a/crates/tauri-schema-generator/schemas/config.schema.json
+++ b/crates/tauri-schema-generator/schemas/config.schema.json
@@ -1104,7 +1104,7 @@
       ]
     },
     "Capability": {
-      "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n   \"identifier\": \"main-user-files-write\",\n   \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n   \"windows\": [\n     \"main\"\n   ],\n  \"permissions\": [\n   \"core:default\",\n   \"dialog:open\",\n   {\n     \"identifier\": \"fs:allow-write-text-file\",\n     \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n   },\n  ],\n  \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
+      "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n   \"identifier\": \"main-user-files-write\",\n   \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n   \"windows\": [\n     \"main\"\n   ],\n   \"permissions\": [\n     \"core:default\",\n     \"dialog:open\",\n     {\n       \"identifier\": \"fs:allow-write-text-file\",\n       \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n     },\n   ],\n   \"platforms\": [\"macOS\",\"windows\"]\n }\n ```",
       "type": "object",
       "required": [
         "identifier",
@@ -1151,7 +1151,7 @@
           }
         },
         "permissions": {
-          "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n  \"core:default\",\n  \"shell:allow-open\",\n  \"dialog:open\",\n  {\n    \"identifier\": \"fs:allow-write-text-file\",\n    \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n  }\n ```",
+          "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n   \"core:default\",\n   \"shell:allow-open\",\n   \"dialog:open\",\n   {\n     \"identifier\": \"fs:allow-write-text-file\",\n     \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n   }\n ]\n ```",
           "type": "array",
           "items": {
             "$ref": "#/definitions/PermissionEntry"
diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs
index e0df92ecea08..06fa0eda0909 100644
--- a/crates/tauri/src/webview/mod.rs
+++ b/crates/tauri/src/webview/mod.rs
@@ -754,6 +754,13 @@ fn main() {
     self
   }
 
+  /// Whether the webview should be focused or not.
+  #[must_use]
+  pub fn focused(mut self, focus: bool) -> Self {
+    self.webview_attributes.focus = focus;
+    self
+  }
+
   /// Sets the webview to automatically grow and shrink its size and position when the parent window resizes.
   #[must_use]
   pub fn auto_resize(mut self) -> Self {
diff --git a/crates/tauri/src/webview/plugin.rs b/crates/tauri/src/webview/plugin.rs
index ca8fd24eea6d..0856e254e65f 100644
--- a/crates/tauri/src/webview/plugin.rs
+++ b/crates/tauri/src/webview/plugin.rs
@@ -22,6 +22,10 @@ mod desktop_commands {
     WebviewWindowBuilder,
   };
 
+  fn default_true() -> bool {
+    true
+  }
+
   #[derive(Debug, PartialEq, Clone, Deserialize)]
   #[serde(rename_all = "camelCase")]
   pub struct WebviewConfig {
@@ -35,6 +39,8 @@ mod desktop_commands {
     height: f64,
     #[serde(default)]
     transparent: bool,
+    #[serde(default = "default_true")]
+    focus: bool,
     #[serde(default)]
     accept_first_mouse: bool,
     window_effects: Option<WindowEffectsConfig>,
@@ -44,6 +50,23 @@ mod desktop_commands {
     zoom_hotkeys_enabled: bool,
   }
 
+  #[cfg(feature = "unstable")]
+  impl<R: Runtime> crate::webview::WebviewBuilder<R> {
+    fn from_webview_config(label: String, config: WebviewConfig) -> Self {
+      let mut builder = Self::new(label, config.url);
+      builder.webview_attributes.user_agent = config.user_agent;
+      builder.webview_attributes.drag_drop_handler_enabled =
+        config.drag_drop_enabled.unwrap_or(true);
+      builder.webview_attributes.transparent = config.transparent;
+      builder.webview_attributes.focus = config.focus;
+      builder.webview_attributes.accept_first_mouse = config.accept_first_mouse;
+      builder.webview_attributes.window_effects = config.window_effects;
+      builder.webview_attributes.incognito = config.incognito;
+      builder.webview_attributes.zoom_hotkeys_enabled = config.zoom_hotkeys_enabled;
+      builder
+    }
+  }
+
   #[derive(Serialize)]
   pub struct WebviewRef {
     window_label: String,
@@ -89,21 +112,18 @@ mod desktop_commands {
       .manager()
       .get_window(&window_label)
       .ok_or(crate::Error::WindowNotFound)?;
-    let mut builder = crate::webview::WebviewBuilder::new(label, options.url);
 
-    builder.webview_attributes.user_agent = options.user_agent;
-    builder.webview_attributes.drag_drop_handler_enabled =
-      options.drag_drop_enabled.unwrap_or(true);
-    builder.webview_attributes.transparent = options.transparent;
-    builder.webview_attributes.accept_first_mouse = options.accept_first_mouse;
-    builder.webview_attributes.window_effects = options.window_effects;
-    builder.webview_attributes.incognito = options.incognito;
-    builder.webview_attributes.zoom_hotkeys_enabled = options.zoom_hotkeys_enabled;
+    let x = options.x;
+    let y = options.y;
+    let width = options.width;
+    let height = options.height;
+
+    let builder = crate::webview::WebviewBuilder::from_webview_config(label, options);
 
     window.add_child(
       builder,
-      tauri_runtime::dpi::LogicalPosition::new(options.x, options.y),
-      tauri_runtime::dpi::LogicalSize::new(options.width, options.height),
+      tauri_runtime::dpi::LogicalPosition::new(x, y),
+      tauri_runtime::dpi::LogicalSize::new(width, height),
     )?;
 
     Ok(())
diff --git a/crates/tauri/src/webview/webview_window.rs b/crates/tauri/src/webview/webview_window.rs
index ee1878e72252..853d5406452d 100644
--- a/crates/tauri/src/webview/webview_window.rs
+++ b/crates/tauri/src/webview/webview_window.rs
@@ -476,10 +476,11 @@ impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
   #[must_use]
   #[deprecated(
     since = "1.2.0",
-    note = "The window is automatically focused by default. This function Will be removed in 2.0.0. Use `focused` instead."
+    note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
   )]
   pub fn focus(mut self) -> Self {
     self.window_builder = self.window_builder.focused(true);
+    self.webview_builder = self.webview_builder.focused(true);
     self
   }
 
@@ -487,6 +488,7 @@ impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
   #[must_use]
   pub fn focused(mut self, focused: bool) -> Self {
     self.window_builder = self.window_builder.focused(focused);
+    self.webview_builder = self.webview_builder.focused(focused);
     self
   }
 
diff --git a/crates/tauri/src/window/mod.rs b/crates/tauri/src/window/mod.rs
index ab0e8cc7fe10..9b8e02b8ef7a 100644
--- a/crates/tauri/src/window/mod.rs
+++ b/crates/tauri/src/window/mod.rs
@@ -531,7 +531,7 @@ impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
   #[must_use]
   #[deprecated(
     since = "1.2.0",
-    note = "The window is automatically focused by default. This function Will be removed in 2.0.0. Use `focused` instead."
+    note = "The window is automatically focused by default. This function Will be removed in 3.0.0. Use `focused` instead."
   )]
   pub fn focus(mut self) -> Self {
     self.window_builder = self.window_builder.focused(true);
diff --git a/packages/api/src/webview.ts b/packages/api/src/webview.ts
index 5b16f058b48e..e04252a95018 100644
--- a/packages/api/src/webview.ts
+++ b/packages/api/src/webview.ts
@@ -684,6 +684,12 @@ interface WebviewOptions {
    * WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.
    */
   transparent?: boolean
+  /**
+   * Whether the webview should have focus or not
+   *
+   * @since 2.1.0
+   */
+  focus?: boolean
   /**
    * Whether the drag and drop is enabled or not on the webview. By default it is enabled.
    *


Test patch: