No errors appear in the console. But I recorded a video for reference.
This happens on chrome, firefox and safari. On mobile safari it doesn’t happen.
Your video link is broken!
Excuse me, I didn’t quite understand that. Indeed, you’re right: when clicking on a date in the calendar, the event creation modal opens, but with the “Do you want to abandon?” button. Yes, indeed, there’s a little bug ![]()
For your information, I’ve added a “+ More Info” button for my users who don’t think to click the title to access the topic. I borrowed the idea from @nathank’s “Add to Calendar” button.
Place the script in a theme component under the General /head section.
<script>
(() => {
const eventInfoSelector = ".event-header .event-info";
const eventCardSelector = ".fc-popover, .event-preview, .discourse-post-event";
// Clean CSS injected and adapted for Discourse themes (Light/Dark)
const style = document.createElement("style");
style.innerHTML = `
.custom-topic-info-btn {
display: flex !important;
align-items: center;
justify-content: center;
width: 40%; /* Takes full width for a clean look under the title */
box-sizing: border-box;
margin: 12px 0 6px 0;
padding: 10px 16px;
/* Using native Discourse variables */
background-color: var(--tertiary) !important; /* Accent color (e.g., blue) */
color: var(--secondary) !important; /* Contrasting text color */
border-radius: 8px;
font-weight: 700;
text-decoration: none !important;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
transition: background-color 0.2s ease, transform 0.1s ease;
}
/* Hover effect */
.custom-topic-info-btn:hover {
background-color: var(--tertiary-hover) !important;
color: var(--secondary) !important;
transform: translateY(-1px);
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
}
/* Click effect */
.custom-topic-info-btn:active {
transform: translateY(0);
}
/* SVG icon style */
.custom-topic-info-btn .btn-icon-svg {
margin-right: 8px;
width: 16px;
height: 16px;
fill: currentColor;
}
`;
document.head.appendChild(style);
const findTopicLink = (container) => {
if (!container) return null;
const links = [...container.querySelectorAll('a[href*="/t/"]')];
if (links.length) return links[0].href;
return null;
};
const createTopicInfoButton = () => {
const eventInfo = document.querySelector(eventInfoSelector);
if (!eventInfo || eventInfo.querySelector(".custom-topic-info-btn")) return;
const card = eventInfo.closest(eventCardSelector) || document;
const topicUrl = findTopicLink(card);
if (!topicUrl) return;
const button = document.createElement("a");
button.className = "btn custom-topic-info-btn";
button.title = "View full topic";
button.href = topicUrl;
// Add a harmonized SVG Info icon
button.innerHTML = `
<svg class="btn-icon-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336h24V240h-24c-13.3 0-24-10.7-24-24s10.7-24 24-24h40c13.3 0 24 10.7 24 24v120h24c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-144a32 32 0 1 1 0-64 32 32 0 1 1 0 64z"/>
</svg>
<span class="d-button-label">More info</span>
`;
if (eventInfo.firstElementChild) {
eventInfo.insertBefore(button, eventInfo.firstElementChild.nextSibling);
} else {
eventInfo.appendChild(button);
}
};
const observer = new MutationObserver(() => createTopicInfoButton());
observer.observe(document.body, { childList: true, subtree: true });
createTopicInfoButton();
})();
</script>
Here’s a preview:
Or alternatively, this code:
<script>
(() => {
const eventCardSelector = ".fc-popover, .event-preview, .discourse-post-event";
// Injected CSS for a clean and modern look
const style = document.createElement("style");
style.innerHTML = `
.custom-topic-info-wrapper {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--primary-low); /* Subtle separator line */
width: 100%;
display: flex;
justify-content: center;
}
.custom-topic-info-btn {
display: flex !important;
align-items: center;
justify-content: center;
width: 100%;
box-sizing: border-box;
padding: 8px 16px;
/* Elegant Outline style */
background-color: transparent !important;
color: var(--tertiary) !important;
border: 1px solid var(--tertiary) !important;
border-radius: 6px;
font-weight: 600;
text-decoration: none !important;
transition: all 0.2s ease;
cursor: pointer;
}
/* Hover effect: button fills with color */
.custom-topic-info-btn:hover {
background-color: var(--tertiary) !important;
color: var(--secondary) !important;
border-color: var(--tertiary) !important;
}
/* Align the info icon */
.custom-topic-info-btn .btn-icon-svg {
margin-right: 8px;
width: 16px;
height: 16px;
fill: currentColor;
}
`;
document.head.appendChild(style);
const findTopicLink = (container) => {
if (!container) return null;
const links = [...container.querySelectorAll('a[href*="/t/"]')];
if (links.length) return links[0].href;
return null;
};
const createTopicInfoButton = () => {
const cards = document.querySelectorAll(eventCardSelector);
cards.forEach(card => {
if (card.querySelector(".custom-topic-info-btn")) return;
const topicUrl = findTopicLink(card);
if (!topicUrl) return;
const wrapper = document.createElement("div");
wrapper.className = "custom-topic-info-wrapper";
const button = document.createElement("a");
button.className = "btn custom-topic-info-btn";
button.title = "View full topic";
button.href = topicUrl;
// "i" Info icon + New actionable text
button.innerHTML = `
<svg class="btn-icon-svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336h24V240h-24c-13.3 0-24-10.7-24-24s10.7-24 24-24h40c13.3 0 24 10.7 24 24v120h24c13.3 0 24 10.7 24 24s-10.7 24-24 24H216c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-144a32 32 0 1 1 0-64 32 32 0 1 1 0 64z"/>
</svg>
<span class="d-button-label">View topic</span>
`;
wrapper.appendChild(button);
// Position above the response options (Going, etc.)
const actionsContainer = card.querySelector(".status-and-options, .event-actions");
const infoContainer = card.querySelector(".event-info");
if (actionsContainer && actionsContainer.parentNode) {
actionsContainer.parentNode.insertBefore(wrapper, actionsContainer);
} else if (infoContainer) {
infoContainer.appendChild(wrapper);
} else {
card.appendChild(wrapper);
}
});
};
const observer = new MutationObserver(() => createTopicInfoButton());
observer.observe(document.body, { childList: true, subtree: true });
createTopicInfoButton();
})();
</script>
Here’s a preview of the result:
You have the choice ![]()
You’ve really improved how easy it is to create an event since the latest updates ![]()
However, I wanted to know if there’s a setting that prevents creating an event when a user clicks in the calendar. Sometimes, instead of clicking on an event, they click nearby, which opens a modal to create a new event ![]()
Thank you.
I know I’m being a pain, but I have another question or suggestion regarding expired events. They could be deleted automatically since they’re no longer of any use, it seems the events plugin used to do this automatically.
Currently, I do it manually, so if there’s a way to save time ![]()
Thanks to the team
Is there any way for the location in the event to do a lookup like is done in google calendar or facebook events, a) to aid the user in picking the location, and b) so the location is clickable to a map application?
(I wasn’t able to find any solution by searching but maybe my search prompts weren’t good)
The Locations Plugin 🌍 does have that sort of functionality, but only integrates with the alternative Events Plugin 📅.
The dev (@merefield) might be open to integrating it with the official plugin, but I imagine that would be quite a bit of work to establish and maintain - so you’d definitely need to sponsor the work for it to happen.
I’ve been trying to look at that Events Plugin, but get stuck at
as the site has been down for months.
It might be worth putting in a formal feature request in Contribute > Feature (tagged calendar-and-events) for consideration. I can imagine it would be a feasible thing - and it has the potential to be high value for many.
later…
@lou has indeed done so here:
A post was merged into an existing topic: Event location map support

