Claude + Webflow MCP
Multi-Collection CMS Filter & Search Setup via Claude + Webflow MCP
Claude adds a flat filter-keys field to each collection and backfills every item over MCP; a 2 KB script then filters and searches several collection lists as one, with shareable URLs.
Works in Webflow Framer React Zero CLS
Customize before you copy
Showing the Webflow version
You are a senior CMS engineer. Set up instant filtering and search across several CMS collections shown as one library (e.g. Resources + Case Studies + Templates).
Part 1 — Data (do this through the CMS connection, after showing me the plan):
- Inspect each collection and list the fields that matter for filtering (category, industry, type, multi-references).
- Add one plain-text field "Filter keys" to each collection. For every item, write a space-separated list of lowercase keys, prefixed by facet: "type:case-study cat:fintech ind:saas". Multi-references become several keys.
- Backfill every existing item, in batches, and report how many you updated per collection. Don't touch any other field.
- Tell me how to keep the keys current for new items (an editor checklist, or a re-run of this prompt).
Part 2 — Front end:
- Filter pills (one active at a time, plus "All") and a search input that matches title and keys, debounced about 120ms.
- Items from all collections are filtered together as one set.
- Matching items fade and rise in over 0.8s with "expo.out"; hidden items are removed from layout (no empty gaps) and from the accessibility tree.
- A polite live region announces "N results", and an empty state appears when nothing matches.
- Sync the state to the URL (?filter=cat:fintech&q=pricing) with history.replaceState, and read it on load, so filtered views are shareable.
Constraints: no third-party filter library, under 3 KB of script, works with the CMS's pagination limits (tell me the limit and how to load all items if a collection exceeds it).
Target platform: Webflow.
- Build the structure as native Webflow Designer elements with Client-First class names (section_[name], [name]_component, [name]_item). No div soup from an HTML embed unless I ask for one.
- Hook every behaviour to custom attributes (data-gsap="…"), never to class names, so designers can restyle without breaking the script.
- Load GSAP through Webflow's built-in GSAP integration (Site settings) or the jsDelivr CDN tags, and put the init script in Page settings → Before </body> tag, wrapped in Webflow.push(() => { … }).
- Say which parts go in Designer styles, which in a page-head <style>, and which in the body script.
- Use the Webflow MCP server for Part 1 (list collections, create the field, update items in batches). In the Designer, bind each Collection Item's custom attribute data-filter-keys to the new field and data-filter-text to the Name. Collection lists render at most 100 items per list, so paginate and load all pages, or keep each list under 100.
Motion timing: "Editorial". Use a base duration of 0.8s, ease "expo.out" (CSS: cubic-bezier(0.16, 1, 0.3, 1)), stagger 0.08s, scrub smoothing 0.8, and springs of stiffness 220 / damping 22, everywhere a duration, ease or spring appears.<!-- Designer:
filter_pills: buttons [data-filter="all"], [data-filter="cat:fintech"], …
filter_search: input [data-filter-search]
filter_list [data-filter-list]: one wrapper holding several Collection Lists
each Collection Item: data-filter-keys = "Filter keys" field, data-filter-text = Name
filter_count [data-filter-count] [aria-live=polite]; filter_empty [data-filter-empty] [hidden] -->
<!-- Page settings > Inside <head> -->
<style>
[data-filter-keys][hidden], [data-filter-empty][hidden] { display: none !important; }
</style>
<!-- Page settings > Before </body> tag -->
<script>
(() => {
const root = document.querySelector("[data-filter-list]");
if (!root) return;
const items = [...root.querySelectorAll("[data-filter-keys]")];
const pills = [...document.querySelectorAll("[data-filter]")];
const search = document.querySelector("[data-filter-search]");
const count = document.querySelector("[data-filter-count]");
const empty = document.querySelector("[data-filter-empty]");
const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
const url = new URL(location.href);
let key = url.searchParams.get("filter") || "all";
let q = url.searchParams.get("q") || "";
if (search) search.value = q;
const apply = () => {
const words = q.toLowerCase().split(/\s+/).filter(Boolean);
let shown = 0;
items.forEach((el) => {
const keys = " " + el.dataset.filterKeys.toLowerCase() + " ";
const text = (el.dataset.filterText || el.textContent).toLowerCase() + keys;
const ok = (key === "all" || keys.includes(" " + key + " ")) && words.every((w) => text.includes(w));
const wasHidden = el.hidden;
el.hidden = !ok;
if (!ok) return;
shown++;
if (wasHidden && !reduce) {
el.animate([{ opacity: 0, transform: "translateY(8px)" }, { opacity: 1, transform: "none" }],
{ duration: 800, easing: "cubic-bezier(0.16, 1, 0.3, 1)" });
}
});
pills.forEach((p) => p.setAttribute("aria-pressed", String(p.dataset.filter === key)));
if (count) count.textContent = shown + (shown === 1 ? " result" : " results");
if (empty) empty.hidden = shown > 0;
key === "all" ? url.searchParams.delete("filter") : url.searchParams.set("filter", key);
q ? url.searchParams.set("q", q) : url.searchParams.delete("q");
history.replaceState(null, "", url);
};
pills.forEach((p) => p.addEventListener("click", () => { key = p.dataset.filter; apply(); }));
let timer;
search?.addEventListener("input", () => {
clearTimeout(timer);
timer = setTimeout(() => { q = search.value.trim(); apply(); }, 120);
});
apply();
})();
</script>3-step implementation guide
Step 1
DOM & attribute setup
Decide your facets (type, category, industry) and add one plain-text "Filter keys" field to every collection that appears in the library. Bind it to a data attribute on each collection item.
Step 2
Prompt Claude or drop in the snippet
Paste the prompt into Claude with your CMS connected: it shows the plan, then backfills keys like "type:case-study cat:fintech" for every item. Drop in the snippet for pills, search and URL sync.
Step 3
Mobile & Core Web Vitals check
Check the item count against the CMS (paginated lists can hide items), share a filtered URL in a private window to confirm it restores, and run Lighthouse on mobile to confirm the script costs nothing noticeable.
Building a full site like this?
Skip the manual setup — I ship complete Figma-to-Webflow & Framer builds in 5–10 business days, or can wire this exact interaction into your live site in 48 hours ($250).