diff --git a/Package.swift b/Package.swift
index bcec957c2be3321cb1b9f1bcc1dd176814764b54..c53f1bb2c4a4aec111c8a015e8de375ea9a34605 100644
--- a/Package.swift
+++ b/Package.swift
@@ -678,6 +678,7 @@ let package = Package(
                     "Integration",
                     "Presentation",
                     "ContactFeature",
+                    "CollectionView",
                     "DependencyInjection",
                     .product(
                         name: "DifferenceKit",
diff --git a/Sources/ContactListFeature/Controllers/ContactListController.swift b/Sources/ContactListFeature/Controllers/ContactListController.swift
index 34612913362943bf2f5de5c6819a14c282c84af9..aab6f249a4559cf4b340529173a7760157e837cf 100644
--- a/Sources/ContactListFeature/Controllers/ContactListController.swift
+++ b/Sources/ContactListFeature/Controllers/ContactListController.swift
@@ -3,6 +3,7 @@ import Theme
 import Shared
 import Combine
 import XXModels
+import CollectionView
 import DependencyInjection
 
 public final class ContactListController: UIViewController {
@@ -36,23 +37,18 @@ public final class ContactListController: UIViewController {
 
     private func setupCollectionView() {
         screenView.collectionView.delegate = self
-        screenView.collectionView.register(AvatarCell.self)
         screenView.collectionView.dataSource = dataSource
         screenView.collectionView.tintColor = Asset.neutralDark.color
+        CellFactory.contactListCellFactory.register(in: screenView.collectionView)
 
         dataSource = IndexedContactList(
             collectionView: screenView.collectionView
         ) { collectionView, indexPath, contact in
-            let cell: AvatarCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
-            let name = (contact.nickname ?? contact.username) ?? "Fetching username..."
-
-            cell.set(
-                image: contact.photo,
-                h1Text: name,
-                showSeparator: false
+            CellFactory.contactListCellFactory.build(
+                for: contact,
+                in: collectionView,
+                at: indexPath
             )
-
-            return cell
         }
     }
 
diff --git a/Sources/ContactListFeature/Controllers/CreateGroupController.swift b/Sources/ContactListFeature/Controllers/CreateGroupController.swift
index a8c75d45d6289c1fe8fd5a9380100664b0e85b91..137851c728584310312de2551d3811d90ae1342f 100644
--- a/Sources/ContactListFeature/Controllers/CreateGroupController.swift
+++ b/Sources/ContactListFeature/Controllers/CreateGroupController.swift
@@ -4,6 +4,7 @@ import Models
 import Shared
 import Combine
 import XXModels
+import CollectionView
 import DependencyInjection
 
 public final class CreateGroupController: UIViewController {
@@ -65,36 +66,29 @@ public final class CreateGroupController: UIViewController {
     }
 
     private func setupCollectionViews() {
-        screenView.bottomCollectionView.register(AvatarCell.self)
-        screenView.topCollectionView.register(CreateGroupCollectionCell.self)
+        CellFactory.createGroupHeroCellFactory
+            .register(in: screenView.topCollectionView)
+        CellFactory.createGroupListCellFactory
+            .register(in: screenView.bottomCollectionView)
 
         topCollectionDataSource = UICollectionViewDiffableDataSource<Int, Contact>(
             collectionView: screenView.topCollectionView
-        ) { [weak viewModel] collectionView, indexPath, contact in
-            let cell: CreateGroupCollectionCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
-
-            let title = (contact.nickname ?? contact.username) ?? ""
-            cell.setup(title: title, image: contact.photo)
-            cell.didTapRemove = { viewModel?.didSelect(contact: contact) }
-
-            return cell
+        ) { collectionView, indexPath, contact in
+            CellFactory.createGroupHeroCellFactory.build(
+                for: contact,
+                in: collectionView,
+                at: indexPath
+            )
         }
 
         bottomCollectionDataSource = UICollectionViewDiffableDataSource<Int, Contact>(
             collectionView: screenView.bottomCollectionView
-        ) { [weak self] collectionView, indexPath, contact in
-            let cell: AvatarCell = collectionView.dequeueReusableCell(forIndexPath: indexPath)
-            let title = (contact.nickname ?? contact.username) ?? ""
-
-            cell.set(image: contact.photo, h1Text: title)
-
-            if let selectedElements = self?.selectedElements, selectedElements.contains(contact) {
-                collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
-            } else {
-                collectionView.deselectItem(at: indexPath, animated: true)
-            }
-
-            return cell
+        ) { collectionView, indexPath, contact in
+            CellFactory.createGroupListCellFactory.build(
+                for: contact,
+                in: collectionView,
+                at: indexPath
+            )
         }
 
         screenView.bottomCollectionView.delegate = self
diff --git a/Sources/ContactListFeature/Utils/ContactListCellConfigurators.swift b/Sources/ContactListFeature/Utils/ContactListCellConfigurators.swift
new file mode 100644
index 0000000000000000000000000000000000000000..69e63438700a764cbf9ad41263b29df966f6a86e
--- /dev/null
+++ b/Sources/ContactListFeature/Utils/ContactListCellConfigurators.swift
@@ -0,0 +1,73 @@
+import Shared
+import XXModels
+import CollectionView
+
+extension CellFactory where Model == Contact {
+    static let contactListCellFactory = CellFactory<Contact>(
+        register: .init(
+            register: { $0.register(AvatarCell.self) }
+        ),
+        build: .init(build: { contact, collectionView, indexPath in
+            let cell: AvatarCell = collectionView.dequeueReusableCell(
+                forIndexPath: indexPath
+            )
+
+            cell.set(
+                image: contact.photo,
+                h1Text: (contact.nickname ?? contact.username) ?? "",
+                showSeparator: false
+            )
+
+            return cell
+        })
+    )
+
+    static let createGroupHeroCellFactory = CellFactory<Contact>(
+        register: .init(
+            register: { $0.register(CreateGroupHeroCollectionCell.self) }
+        ),
+        build: .init(build: { contact, collectionView, indexPath in
+            let name = (contact.nickname ?? contact.username) ?? ""
+
+            let cell: CreateGroupHeroCollectionCell = collectionView.dequeueReusableCell(
+                forIndexPath: indexPath
+            )
+
+            cell.setup(
+                title: name,
+                image: contact.photo,
+                action: {
+                    // viewModel?.didSelect(contact: contact)
+                }
+            )
+
+            return cell
+        })
+    )
+
+    static let createGroupListCellFactory = CellFactory<Contact>(
+        register: .init(
+            register: { $0.register(AvatarCell.self) }
+        ),
+        build: .init(build: { contact, collectionView, indexPath in
+            let name = (contact.nickname ?? contact.username) ?? ""
+
+            let cell: AvatarCell = collectionView.dequeueReusableCell(
+                forIndexPath: indexPath
+            )
+
+            cell.set(
+                image: contact.photo,
+                h1Text: name
+            )
+
+            //if let selectedElements = self?.selectedElements, selectedElements.contains(contact) {
+            //    collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
+            //} else {
+            //    collectionView.deselectItem(at: indexPath, animated: true)
+            //}
+
+            return cell
+        })
+    )
+}
diff --git a/Sources/ContactListFeature/Views/CreateGroupCollectionCell.swift b/Sources/ContactListFeature/Views/CreateGroupHeroCollectionCell.swift
similarity index 71%
rename from Sources/ContactListFeature/Views/CreateGroupCollectionCell.swift
rename to Sources/ContactListFeature/Views/CreateGroupHeroCollectionCell.swift
index 1717365300ab0ae52380cc47e6073f8118684957..e4d4be9e3df8b1bc40c65d672913c27eabbdfa5e 100644
--- a/Sources/ContactListFeature/Views/CreateGroupCollectionCell.swift
+++ b/Sources/ContactListFeature/Views/CreateGroupHeroCollectionCell.swift
@@ -2,14 +2,13 @@ import UIKit
 import Shared
 import Combine
 
-final class CreateGroupCollectionCell: UICollectionViewCell {
-    let titleLabel = UILabel()
-    let removeButton = UIButton()
-    let upperView = UIView()
-    let avatarView = AvatarView()
-
-    var didTapRemove: (() -> Void)?
-    var cancellables = Set<AnyCancellable>()
+final class CreateGroupHeroCollectionCell: UICollectionViewCell {
+    private let upperView = UIView()
+    private let titleLabel = UILabel()
+    private let avatarView = AvatarView()
+    private let removeButton = UIButton()
+    private var didTapAction: (() -> Void)?
+    private var cancellables = Set<AnyCancellable>()
 
     override init(frame: CGRect) {
         super.init(frame: frame)
@@ -29,6 +28,43 @@ final class CreateGroupCollectionCell: UICollectionViewCell {
         contentView.addSubview(upperView)
         contentView.addSubview(removeButton)
 
+        setupConstraints()
+    }
+
+    required init?(coder: NSCoder) { nil }
+
+    override func prepareForReuse() {
+        super.prepareForReuse()
+
+        didTapAction = nil
+        titleLabel.text = nil
+        avatarView.prepareForReuse()
+        cancellables.removeAll()
+    }
+
+    func setup(
+        title: String,
+        image: Data?,
+        action: @escaping () -> Void
+    ) {
+        avatarView.setupProfile(
+            title: title,
+            image: image,
+            size: .large
+        )
+
+        titleLabel.text = title
+        didTapAction = action
+
+        cancellables.removeAll()
+
+        removeButton
+            .publisher(for: .touchUpInside)
+            .sink { [unowned self] in didTapAction?() }
+            .store(in: &cancellables)
+    }
+
+    private func setupConstraints() {
         upperView.snp.makeConstraints {
             $0.top.equalToSuperview()
             $0.left.equalToSuperview()
@@ -58,23 +94,4 @@ final class CreateGroupCollectionCell: UICollectionViewCell {
             $0.bottom.equalToSuperview()
         }
     }
-
-    required init?(coder: NSCoder) { nil }
-
-    override func prepareForReuse() {
-        super.prepareForReuse()
-        titleLabel.text = nil
-        avatarView.prepareForReuse()
-        cancellables.removeAll()
-    }
-
-    func setup(title: String, image: Data?) {
-        titleLabel.text = title
-        avatarView.setupProfile(title: title, image: image, size: .large)
-        cancellables.removeAll()
-
-        removeButton.publisher(for: .touchUpInside)
-            .sink { [unowned self] in didTapRemove?() }
-            .store(in: &cancellables)
-    }
 }