diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart
index 359746f4c..859fd0d70 100644
--- a/flutter/lib/desktop/pages/connection_page.dart
+++ b/flutter/lib/desktop/pages/connection_page.dart
@@ -11,10 +11,12 @@ import 'package:flutter_hbb/models/state_model.dart';
 import 'package:get/get.dart';
 import 'package:url_launcher/url_launcher_string.dart';
 import 'package:window_manager/window_manager.dart';
+import 'package:flutter_hbb/models/peer_model.dart';
 
 import '../../common.dart';
 import '../../common/formatter/id_formatter.dart';
 import '../../common/widgets/peer_tab_page.dart';
+import '../../common/widgets/peer_card.dart';
 import '../../models/platform_model.dart';
 import '../widgets/button.dart';
 
@@ -41,6 +43,15 @@ class _ConnectionPageState extends State<ConnectionPage>
   var svcIsUsingPublicServer = true.obs;
 
   bool isWindowMinimized = false;
+  List<Peer> peers = [];
+  List _frontN<T>(List list, int n) {
+    if (list.length <= n) {
+      return list;
+    } else {
+      return list.sublist(0, n);
+    }
+  }
+  bool isPeersLoading = false;
 
   @override
   void initState() {
@@ -58,12 +69,6 @@ class _ConnectionPageState extends State<ConnectionPage>
     _updateTimer = periodic_immediate(Duration(seconds: 1), () async {
       updateStatus();
     });
-    _idFocusNode.addListener(() {
-      _idInputFocused.value = _idFocusNode.hasFocus;
-      // select all to faciliate removing text, just following the behavior of address input of chrome
-      _idController.selection = TextSelection(
-          baseOffset: 0, extentOffset: _idController.value.text.length);
-    });
     Get.put<IDTextEditingController>(_idController);
     windowManager.addListener(this);
   }
@@ -142,8 +147,66 @@ class _ConnectionPageState extends State<ConnectionPage>
     connect(context, id, isFileTransfer: isFileTransfer);
   }
 
+  Future<void> _fetchPeers() async {
+    setState(() {
+      isPeersLoading = true;
+    });
+    await Future.delayed(Duration(milliseconds: 100));
+    await _getAllPeers();
+    setState(() {
+        isPeersLoading = false;
+      });
+  }
+
+  Future<void> _getAllPeers() async {
+    Map<String, dynamic> recentPeers = jsonDecode(await bind.mainLoadRecentPeersSync());
+    Map<String, dynamic> lanPeers = jsonDecode(await bind.mainLoadLanPeersSync());
+    Map<String, dynamic> abPeers = jsonDecode(await bind.mainLoadAbSync());
+    Map<String, dynamic> groupPeers = jsonDecode(await bind.mainLoadGroupSync());
+
+    Map<String, dynamic> combinedPeers = {};
+
+    void mergePeers(Map<String, dynamic> peers) {
+      if (peers.containsKey("peers")) {
+        dynamic peerData = peers["peers"];
+
+        if (peerData is String) {
+          try {
+            peerData = jsonDecode(peerData);
+          } catch (e) {
+            debugPrint("Error decoding peers: $e");
+            return;
+          }
+        }
+
+        if (peerData is List) {
+          for (var peer in peerData) {
+            if (peer is Map && peer.containsKey("id")) {
+              String id = peer["id"];
+              if (id != null && !combinedPeers.containsKey(id)) {
+                combinedPeers[id] = peer;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    mergePeers(recentPeers);
+    mergePeers(lanPeers);
+    mergePeers(abPeers);
+    mergePeers(groupPeers);
+
+      List<Peer> parsedPeers = [];
+
+    for (var peer in combinedPeers.values) {
+      parsedPeers.add(Peer.fromJson(peer));
+    }
+      peers = parsedPeers;
+  }
+
   /// UI for the remote ID TextField.
-  /// Search for a peer and connect to it if the id exists.
+  /// Search for a peer.
   Widget _buildRemoteIDTextField(BuildContext context) {
     var w = Container(
       width: 320 + 20 * 2,
@@ -171,36 +234,141 @@ class _ConnectionPageState extends State<ConnectionPage>
             Row(
               children: [
                 Expanded(
-                  child: Obx(
-                    () => TextField(
-                      maxLength: 90,
-                      autocorrect: false,
-                      enableSuggestions: false,
-                      keyboardType: TextInputType.visiblePassword,
-                      focusNode: _idFocusNode,
-                      style: const TextStyle(
-                        fontFamily: 'WorkSans',
-                        fontSize: 22,
-                        height: 1.4,
-                      ),
-                      maxLines: 1,
-                      cursorColor:
-                          Theme.of(context).textTheme.titleLarge?.color,
-                      decoration: InputDecoration(
-                          filled: false,
-                          counterText: '',
-                          hintText: _idInputFocused.value
-                              ? null
-                              : translate('Enter Remote ID'),
-                          contentPadding: const EdgeInsets.symmetric(
-                              horizontal: 15, vertical: 13)),
-                      controller: _idController,
-                      inputFormatters: [IDTextInputFormatter()],
-                      onSubmitted: (s) {
-                        onConnect();
-                      },
-                    ),
-                  ),
+                  child: 
+                   Autocomplete<Peer>(
+                    optionsBuilder: (TextEditingValue textEditingValue) {
+                      if (textEditingValue.text == '') {
+                        return const Iterable<Peer>.empty();
+                      }
+                      else if (peers.isEmpty) {
+                         Peer emptyPeer = Peer(
+                          id: '',
+                          username: '',
+                          hostname: '',
+                          alias: '',
+                          platform: '',
+                          tags: [],
+                          hash: '',
+                          forceAlwaysRelay: false,
+                          rdpPort: '',
+                          rdpUsername: '',
+                          loginName: '',
+                        );
+                        return [emptyPeer];
+                      }
+                      else {
+                        String textWithoutSpaces = textEditingValue.text.replaceAll(" ", "");
+                        if (int.tryParse(textWithoutSpaces) != null) {
+                          textEditingValue = TextEditingValue(
+                            text: textWithoutSpaces,
+                            selection: textEditingValue.selection,
+                          );
+                        }
+                        String textToFind = textEditingValue.text.toLowerCase();
+
+                        return peers.where((peer) =>
+                        peer.id.toLowerCase().contains(textToFind) ||
+                        peer.username.toLowerCase().contains(textToFind) ||
+                        peer.hostname.toLowerCase().contains(textToFind) ||
+                        peer.alias.toLowerCase().contains(textToFind))
+                            .toList();
+                      }
+                    },
+
+                    fieldViewBuilder: (BuildContext context,
+                        TextEditingController fieldTextEditingController,
+                        FocusNode fieldFocusNode ,
+                        VoidCallback onFieldSubmitted,
+                        ) {
+                      fieldTextEditingController.text = _idController.text;
+                      fieldFocusNode.addListener(() async {
+                        _idInputFocused.value = fieldFocusNode.hasFocus;
+                        if (fieldFocusNode.hasFocus && !isPeersLoading){
+                          _fetchPeers();
+                        }
+                      });
+                      final textLength = fieldTextEditingController.value.text.length;
+                      // select all to facilitate removing text, just following the behavior of address input of chrome
+                      fieldTextEditingController.selection = TextSelection(baseOffset: 0, extentOffset: textLength);
+                      return Obx(() =>
+                      TextField(
+                        maxLength: 90,
+                        autocorrect: false,
+                        enableSuggestions: false,
+                        keyboardType: TextInputType.visiblePassword,
+                        focusNode: fieldFocusNode,
+                        style: const TextStyle(
+                          fontFamily: 'WorkSans',
+                          fontSize: 22,
+                          height: 1.4,
+                        ),
+                        maxLines: 1,
+                        cursorColor: Theme.of(context).textTheme.titleLarge?.color,
+                        decoration: InputDecoration(
+                            filled: false,
+                            counterText: '',
+                            hintText: _idInputFocused.value
+                                ? null
+                                : translate('Enter Remote ID'),
+                            contentPadding: const EdgeInsets.symmetric(
+                                horizontal: 15, vertical: 13)),
+                        controller: fieldTextEditingController,
+                        inputFormatters: [IDTextInputFormatter()],
+                        onChanged: (v) {
+                          _idController.id = v;
+                        },
+                        onSubmitted: (s) {
+                          if (s == '') {
+                            return;
+                          }
+                          try {
+                            final id = int.parse(s);
+                            _idController.id = s;
+                            onConnect();
+                          } catch (_) {
+                            return;
+                          }
+                        },
+                      ));
+                    },
+                    optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<Peer> onSelected, Iterable<Peer> options) {
+                      double maxHeight = 0;
+                      for (var peer in options) {
+                        if (maxHeight < 200)
+                        maxHeight += 50; };
+                      return Align(
+                        alignment: Alignment.topLeft,
+                        child: ClipRRect(
+                          borderRadius: BorderRadius.circular(5),
+                          child: Material(
+                          elevation: 4,
+                          child: ConstrainedBox(
+                            constraints: BoxConstraints(
+                              maxHeight: maxHeight,
+                              maxWidth: 319,
+                            ),
+                              child: peers.isEmpty && isPeersLoading
+                              ? Container(
+                                    height: 80,
+                                     child: Center( 
+                                      child: CircularProgressIndicator(
+                                        strokeWidth: 2,
+                                      ),
+                                    )
+                                  )
+                              : Padding(
+                              padding: const EdgeInsets.only(top: 5),
+                              child: ListView(
+                                children: options
+                                    .map((peer) => _buildPeerTile(context, peer))
+                                    .toList()
+                              ),
+                            ),
+                          ),
+                        )),
+                      );
+                    },
+                  )
                 ),
               ],
             ),
@@ -229,6 +397,115 @@ class _ConnectionPageState extends State<ConnectionPage>
         constraints: const BoxConstraints(maxWidth: 600), child: w);
   }
 
+  Widget _buildPeerTile(
+      BuildContext context, Peer peer) {
+        final double _tileRadius = 5;
+        final name =
+          '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}';
+        final greyStyle = TextStyle(
+          fontSize: 11,
+          color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6));
+        final child = GestureDetector(
+          onTap: () {
+            setState(() {
+              _idController.id = peer.id;
+              FocusScope.of(context).unfocus();
+            });
+          },
+          child:
+        Container(
+          height: 42,
+          margin: EdgeInsets.only(bottom: 5),
+          child: Row(
+          mainAxisSize: MainAxisSize.max,
+          children: [
+            Container(
+              decoration: BoxDecoration(
+                color: str2color('${peer.id}${peer.platform}', 0x7f),
+                borderRadius: BorderRadius.only(
+                        topLeft: Radius.circular(_tileRadius),
+                        bottomLeft: Radius.circular(_tileRadius),
+                      ),
+              ),
+              alignment: Alignment.center,
+              width: 42,
+              height: null,
+              child: getPlatformImage(peer.platform, size: 30)
+                  .paddingAll(6),
+            ),
+            Expanded(
+              child: Container(
+                decoration: BoxDecoration(
+                  color: Theme.of(context).colorScheme.background,
+                  borderRadius: BorderRadius.only(
+                    topRight: Radius.circular(_tileRadius),
+                    bottomRight: Radius.circular(_tileRadius),
+                  ),
+                ),
+            child: Row(
+              children: [
+                Expanded(
+                  child: Column(
+                    children: [
+                      Row(children: [
+                        getOnline(8, peer.online),
+                        Expanded(
+                            child: Text(
+                          peer.alias.isEmpty ? formatID(peer.id) : peer.alias,
+                          overflow: TextOverflow.ellipsis,
+                          style: Theme.of(context).textTheme.titleSmall,
+                        )),
+                        !peer.alias.isEmpty?
+                        Padding(
+                          padding: const EdgeInsets.only(left: 5, right: 5),
+                          child: Text(
+                            "(${peer.id})",
+                            style: greyStyle,
+                            overflow: TextOverflow.ellipsis,
+                          )
+                        )
+                        : Container(),
+                      ]).marginOnly(top: 2),
+                      Align(
+                        alignment: Alignment.centerLeft,
+                        child: Text(
+                          name,
+                          style: greyStyle,
+                          textAlign: TextAlign.start,
+                          overflow: TextOverflow.ellipsis,
+                        ),
+                      ),
+                    ],
+                  ).marginOnly(top: 2),
+                ),
+              ],
+            ).paddingOnly(left: 10.0, top: 3.0),
+            ),
+        )
+      ],
+    )));
+    final colors =
+        _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList();
+    return Tooltip(
+      message: isMobile
+          ? ''
+          : peer.tags.isNotEmpty
+              ? '${translate('Tags')}: ${peer.tags.join(', ')}'
+              : '',
+      child: Stack(children: [
+        child,
+        if (colors.isNotEmpty)
+          Positioned(
+            top: 5,
+            right: 10,
+            child: CustomPaint(
+              painter: TagPainter(radius: 3, colors: colors),
+            ),
+          )
+      ]),
+    );
+  }
+
   Widget buildStatus() {
     final em = 14.0;
     return Container(
diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs
index 14cc32978..f1d7e5923 100644
--- a/src/flutter_ffi.rs
+++ b/src/flutter_ffi.rs
@@ -955,6 +955,25 @@ pub fn main_load_recent_peers_sync() -> SyncReturn<String> {
     SyncReturn("".to_string())
 }
 
+pub fn main_load_lan_peers_sync() -> SyncReturn<String> {
+    let data = HashMap::from([
+        ("name", "load_lan_peers".to_owned()),
+        (
+            "peers",
+            serde_json::to_string(&get_lan_peers()).unwrap_or_default(),
+        ),
+    ]);
+    return SyncReturn(serde_json::ser::to_string(&data).unwrap_or("".to_owned()));
+}
+
+pub fn main_load_ab_sync() -> SyncReturn<String> {
+    return SyncReturn(serde_json::to_string(&config::Ab::load()).unwrap_or_default());
+}
+
+pub fn main_load_group_sync() -> SyncReturn<String> {
+    return SyncReturn(serde_json::to_string(&config::Group::load()).unwrap_or_default());
+}
+
 pub fn main_load_recent_peers_for_ab(filter: String) -> String {
     let id_filters = serde_json::from_str::<Vec<String>>(&filter).unwrap_or_default();
     let id_filters = if id_filters.is_empty() {