diff --git a/Examples/xx-messenger/Package.swift b/Examples/xx-messenger/Package.swift
index 1254c0e0f58a0028cce730198987a8e2d835039d..95a8720225901da1377b8adaf5625e88e65c02ac 100644
--- a/Examples/xx-messenger/Package.swift
+++ b/Examples/xx-messenger/Package.swift
@@ -69,6 +69,7 @@ let package = Package(
       name: "AppFeature",
       dependencies: [
         .target(name: "AppCore"),
+        .target(name: "ContactFeature"),
         .target(name: "HomeFeature"),
         .target(name: "RegisterFeature"),
         .target(name: "RestoreFeature"),
@@ -158,6 +159,7 @@ let package = Package(
     .target(
       name: "UserSearchFeature",
       dependencies: [
+        .target(name: "ContactFeature"),
         .product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
         .product(name: "ComposablePresentation", package: "swift-composable-presentation"),
         .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"),
diff --git a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
index d8761a65e8dd84a628cb8fb8c67231083c42cff2..03c8442cf0431924977536d9b3e84a6318087279 100644
--- a/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
+++ b/Examples/xx-messenger/Sources/AppFeature/AppEnvironment+Live.swift
@@ -52,11 +52,10 @@ extension AppEnvironment {
               mainQueue: mainQueue,
               bgQueue: bgQueue,
               result: {
-                UserSearchResultEnvironment(
-                  db: dbManager.getDB,
-                  mainQueue: mainQueue,
-                  bgQueue: bgQueue
-                )
+                UserSearchResultEnvironment()
+              },
+              contact: {
+                ContactEnvironment()
               }
             )
           }
diff --git a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift
index 84c78195209c839f51b3d0771a41aad23a10659f..425832e26ee67b4a71bf3bd6086fd3269c26dbad 100644
--- a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift
+++ b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchFeature.swift
@@ -1,5 +1,6 @@
 import ComposableArchitecture
 import ComposablePresentation
+import ContactFeature
 import Foundation
 import XCTestDynamicOverlay
 import XXClient
@@ -17,13 +18,15 @@ public struct UserSearchState: Equatable {
     query: MessengerSearchUsers.Query = .init(),
     isSearching: Bool = false,
     failure: String? = nil,
-    results: IdentifiedArrayOf<UserSearchResultState> = []
+    results: IdentifiedArrayOf<UserSearchResultState> = [],
+    contact: ContactState? = nil
   ) {
     self.focusedField = focusedField
     self.query = query
     self.isSearching = isSearching
     self.failure = failure
     self.results = results
+    self.contact = contact
   }
 
   @BindableState public var focusedField: Field?
@@ -31,14 +34,17 @@ public struct UserSearchState: Equatable {
   public var isSearching: Bool
   public var failure: String?
   public var results: IdentifiedArrayOf<UserSearchResultState>
+  public var contact: ContactState?
 }
 
 public enum UserSearchAction: Equatable, BindableAction {
   case searchTapped
   case didFail(String)
   case didSucceed([Contact])
+  case didDismissContact
   case binding(BindingAction<UserSearchState>)
   case result(id: UserSearchResultState.ID, action: UserSearchResultAction)
+  case contact(ContactAction)
 }
 
 public struct UserSearchEnvironment {
@@ -46,18 +52,21 @@ public struct UserSearchEnvironment {
     messenger: Messenger,
     mainQueue: AnySchedulerOf<DispatchQueue>,
     bgQueue: AnySchedulerOf<DispatchQueue>,
-    result: @escaping () -> UserSearchResultEnvironment
+    result: @escaping () -> UserSearchResultEnvironment,
+    contact: @escaping () -> ContactEnvironment
   ) {
     self.messenger = messenger
     self.mainQueue = mainQueue
     self.bgQueue = bgQueue
     self.result = result
+    self.contact = contact
   }
 
   public var messenger: Messenger
   public var mainQueue: AnySchedulerOf<DispatchQueue>
   public var bgQueue: AnySchedulerOf<DispatchQueue>
   public var result: () -> UserSearchResultEnvironment
+  public var contact: () -> ContactEnvironment
 }
 
 #if DEBUG
@@ -66,7 +75,8 @@ extension UserSearchEnvironment {
     messenger: .unimplemented,
     mainQueue: .unimplemented,
     bgQueue: .unimplemented,
-    result: { .unimplemented }
+    result: { .unimplemented },
+    contact: { .unimplemented }
   )
 }
 #endif
@@ -105,7 +115,15 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe
     state.results = []
     return .none
 
-  case .binding(_), .result(_, _):
+  case .didDismissContact:
+    state.contact = nil
+    return .none
+
+  case .result(let id, action: .tapped):
+    state.contact = ContactState()
+    return .none
+
+  case .binding(_), .result(_, _), .contact(_):
     return .none
   }
 }
@@ -116,3 +134,10 @@ public let userSearchReducer = Reducer<UserSearchState, UserSearchAction, UserSe
   action: /UserSearchAction.result(id:action:),
   environment: { $0.result() }
 )
+.presenting(
+  contactReducer,
+  state: .keyPath(\.contact),
+  id: .notNil(), // TODO: use Contact.ID
+  action: /UserSearchAction.contact,
+  environment: { $0.contact() }
+)
diff --git a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift
index e149ac2a9f4d7485a80331e6ac816e87f8b41aaf..f0416b3a53542ef4195a66ca077617327d62737c 100644
--- a/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift
+++ b/Examples/xx-messenger/Sources/UserSearchFeature/UserSearchView.swift
@@ -1,4 +1,6 @@
 import ComposableArchitecture
+import ComposablePresentation
+import ContactFeature
 import SwiftUI
 import XXMessengerClient
 
@@ -96,6 +98,14 @@ public struct UserSearchView: View {
       .onChange(of: viewStore.focusedField) { focusedField = $0 }
       .onChange(of: focusedField) { viewStore.send(.set(\.$focusedField, $0)) }
       .navigationTitle("User Search")
+      .background(NavigationLinkWithStore(
+        store.scope(
+          state: \.contact,
+          action: UserSearchAction.contact
+        ),
+        onDeactivate: { viewStore.send(.didDismissContact) },
+        destination: ContactView.init(store:)
+      ))
     }
   }
 }
diff --git a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift b/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift
index 4311b515ccc209d9f84738bc5b57d7f1a8d7620e..285d359e7a8582ba52a10a8308f447f1f251b198 100644
--- a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchFeatureTests.swift
@@ -1,4 +1,5 @@
 import ComposableArchitecture
+import ContactFeature
 import XCTest
 import XXClient
 import XXMessengerClient
@@ -87,4 +88,37 @@ final class UserSearchFeatureTests: XCTestCase {
       $0.results = []
     }
   }
+
+  func testResultTapped() {
+    let store = TestStore(
+      initialState: UserSearchState(
+        results: [
+          .init(
+            id: "contact-id".data(using: .utf8)!,
+            xxContact: .unimplemented("contact-data".data(using: .utf8)!)
+          )
+        ]
+      ),
+      reducer: userSearchReducer,
+      environment: .unimplemented
+    )
+
+    store.send(.result(id: "contact-id".data(using: .utf8)!, action: .tapped)) {
+      $0.contact = ContactState()
+    }
+  }
+
+  func testDismissingContact() {
+    let store = TestStore(
+      initialState: UserSearchState(
+        contact: ContactState()
+      ),
+      reducer: userSearchReducer,
+      environment: .unimplemented
+    )
+
+    store.send(.didDismissContact) {
+      $0.contact = nil
+    }
+  }
 }
diff --git a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift b/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift
index e776f803978b12c467701f371496d9bdd83d0a11..c8f2a99b92b35b645c1d3e94462e6353ec4d33fc 100644
--- a/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift
+++ b/Examples/xx-messenger/Tests/UserSearchFeatureTests/UserSearchResultFeatureTests.swift
@@ -1,9 +1,7 @@
-import Combine
 import ComposableArchitecture
 import XCTest
 import XCTestDynamicOverlay
 import XXClient
-import XXModels
 @testable import UserSearchFeature
 
 final class UserSearchResultFeatureTests: XCTestCase {
@@ -26,41 +24,14 @@ final class UserSearchResultFeatureTests: XCTestCase {
       environment: .unimplemented
     )
 
-    var dbDidFetchContacts: [XXModels.Contact.Query] = []
-    let dbContactsPublisher = PassthroughSubject<[XXModels.Contact], Error>()
-
-    store.environment.mainQueue = .immediate
-    store.environment.bgQueue = .immediate
-    store.environment.db.run = {
-      var db: Database = .failing
-      db.fetchContactsPublisher.run = { query in
-        dbDidFetchContacts.append(query)
-        return dbContactsPublisher.eraseToAnyPublisher()
-      }
-      return db
-    }
-
     store.send(.start) {
       $0.username = "contact-username"
       $0.email = "contact-email"
       $0.phone = "contact-phone"
     }
-
-    XCTAssertNoDifference(dbDidFetchContacts, [
-      .init(id: ["contact-id".data(using: .utf8)!])
-    ])
-
-    let dbContact = XXModels.Contact(id: "contact-id".data(using: .utf8)!)
-    dbContactsPublisher.send([dbContact])
-
-    store.receive(.didUpdateContact(dbContact)) {
-      $0.dbContact = dbContact
-    }
-
-    dbContactsPublisher.send(completion: .finished)
   }
 
-  func testSendRequest() {
+  func testTapped() {
     let store = TestStore(
       initialState: UserSearchResultState(
         id: "contact-id".data(using: .utf8)!,
@@ -70,6 +41,6 @@ final class UserSearchResultFeatureTests: XCTestCase {
       environment: .unimplemented
     )
 
-    store.send(.sendRequestButtonTapped)
+    store.send(.tapped)
   }
 }