diff --git a/apps/researcher/src/app/[locale]/objects/[id]/object-lists-actions.ts b/apps/researcher/src/app/[locale]/objects/[id]/object-lists-actions.ts
new file mode 100644
index 000000000..38a7119c9
--- /dev/null
+++ b/apps/researcher/src/app/[locale]/objects/[id]/object-lists-actions.ts
@@ -0,0 +1,35 @@
+'use server';
+
+import {getCommunityBySlug} from '@/lib/community';
+import {objectList} from '@colonial-collections/database';
+import {ObjectItemBeingCreated} from '@colonial-collections/database';
+import {revalidatePath} from 'next/cache';
+
+export async function getCommunityLists(communityId: string, objectId: string) {
+ return objectList.getByCommunityId(communityId, {objectIri: objectId});
+}
+
+interface AddObjectToListProps {
+ objectItem: ObjectItemBeingCreated;
+ communityId: string;
+}
+
+export async function addObjectToList({
+ objectItem,
+ communityId,
+}: AddObjectToListProps) {
+ const addObjectPromise = objectList.addObject(objectItem);
+ const getCommunityPromise = getCommunityBySlug(communityId);
+ const [community] = await Promise.all([
+ getCommunityPromise,
+ addObjectPromise,
+ ]);
+
+ revalidatePath(`/[locale]/communities/${community.slug}`, 'page');
+}
+
+export async function removeObjectFromList(id: number, communityId: string) {
+ await objectList.removeObject(id);
+ const community = await getCommunityBySlug(communityId);
+ revalidatePath(`/[locale]/communities/${community.slug}`, 'page');
+}
diff --git a/apps/researcher/src/app/[locale]/objects/[id]/object-lists-menu.tsx b/apps/researcher/src/app/[locale]/objects/[id]/object-lists-menu.tsx
new file mode 100644
index 000000000..aa89ee64a
--- /dev/null
+++ b/apps/researcher/src/app/[locale]/objects/[id]/object-lists-menu.tsx
@@ -0,0 +1,170 @@
+'use client';
+
+import {useTranslations} from 'next-intl';
+import {Fragment, useState, useEffect} from 'react';
+import {Menu, Transition} from '@headlessui/react';
+import {ChevronDownIcon} from '@heroicons/react/20/solid';
+import {CheckIcon} from '@heroicons/react/24/outline';
+import {useUser} from '@clerk/nextjs';
+import {
+ getCommunityLists,
+ addObjectToList,
+ removeObjectFromList,
+} from './object-lists-actions';
+import {ObjectList} from '@colonial-collections/database';
+import {useNotifications} from 'ui';
+
+interface CommunityMenuItemsProps {
+ communityId: string;
+ objectId: string;
+ userId: string;
+}
+
+function CommunityMenuItems({
+ communityId,
+ objectId,
+ userId,
+}: CommunityMenuItemsProps) {
+ const [objectLists, setObjectLists] = useState
([]);
+ const t = useTranslations('ObjectDetails');
+ const {addNotification} = useNotifications();
+
+ async function listClick(objectList: ObjectList) {
+ const isEmptyList = !objectList.objects!.length;
+
+ if (isEmptyList) {
+ try {
+ await addObjectToList({
+ objectItem: {
+ objectIri: objectId,
+ objectListId: objectList.id,
+ createdBy: userId,
+ },
+ communityId,
+ });
+
+ addNotification({
+ id: 'objectAddedToList',
+ message: t.rich('objectAddedToList', {
+ name: () => {objectList.name},
+ }),
+ type: 'success',
+ });
+ } catch (err) {
+ addNotification({
+ id: 'errorObjectAddedToList',
+ message: t('errorObjectAddedToList'),
+ type: 'error',
+ });
+ }
+ } else {
+ try {
+ await removeObjectFromList(objectList.objects![0].id, communityId);
+
+ addNotification({
+ id: 'objectRemovedFromList',
+ message: t.rich('objectRemovedFromList', {
+ name: () => {objectList.name},
+ }),
+ type: 'success',
+ });
+ } catch (err) {
+ addNotification({
+ id: 'errorObjectRemovedFromList',
+ message: t('errorObjectRemovedFromList'),
+ type: 'error',
+ });
+ }
+ }
+ }
+
+ useEffect(() => {
+ async function getLists() {
+ const lists = await getCommunityLists(communityId, objectId);
+ setObjectLists(lists);
+ }
+ getLists();
+ }, [communityId, objectId]);
+
+ if (!objectLists.length) {
+ return (
+
+ {t('noListsInCommunity')}
+
+ );
+ }
+
+ return (
+
+ {objectLists.map(objectList => (
+
+
+
+ ))}
+
+ );
+}
+
+interface ObjectListsMenuProps {
+ objectId: string;
+}
+
+export default function ObjectListsMenu({objectId}: ObjectListsMenuProps) {
+ const t = useTranslations('ObjectDetails');
+ const {user} = useUser();
+
+ if (!user || !user.organizationMemberships.length) {
+ return null;
+ }
+
+ const communities = user.organizationMemberships.map(
+ membership => membership.organization
+ );
+
+ return (
+
+ );
+}
diff --git a/apps/researcher/src/app/[locale]/objects/[id]/page.tsx b/apps/researcher/src/app/[locale]/objects/[id]/page.tsx
index a45ae25e5..9341386fb 100644
--- a/apps/researcher/src/app/[locale]/objects/[id]/page.tsx
+++ b/apps/researcher/src/app/[locale]/objects/[id]/page.tsx
@@ -18,6 +18,9 @@ import {
import useCurrentPublisher from './useCurrentPublisher';
import {env} from 'node:process';
import {formatDateCreated} from './format-date-created';
+import ObjectListsMenu from './object-lists-menu';
+import {SignedIn} from '@clerk/nextjs';
+import {Notifications} from 'ui';
// Revalidate the page
export const revalidate = 0;
@@ -106,16 +109,9 @@ export default async function Details({params}: Props) {