`; document.body.appendChild(el); return el; } const bubble = ensureBubble(); const elH = bubble.querySelector("#tt-title"); const elB = bubble.querySelector("#tt-body"); const elClose = bubble.querySelector(".tt-close"); // ---------------- Parse [[term|heading|body]] anywhere ---------------- const TOKEN_RE = /\[\[([^|\]]+)\|([^|\]]+)\|([^\]]+)\]\]/g; const BLOCK_SKIP = new Set(["SCRIPT","STYLE","NOSCRIPT","TEXTAREA","INPUT","SELECT","CODE","PRE","TEMPLATE","IFRAME"]); function shouldSkipTextNode(n){ let el = n.parentElement; while (el){ if (BLOCK_SKIP.has(el.tagName) || el.isContentEditable) return true; el = el.parentElement; } return false; } const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT); const textNodes = []; while (walker.nextNode()){ const n = walker.currentNode; if (!n.nodeValue || shouldSkipTextNode(n)) continue; if (TOKEN_RE.test(n.nodeValue)) textNodes.push(n); TOKEN_RE.lastIndex = 0; } textNodes.forEach(node => { const frag = document.createDocumentFragment(); const insideLink = !!node.parentElement.closest("a"); let text = node.nodeValue, last = 0; TOKEN_RE.lastIndex = 0; let m; while ((m = TOKEN_RE.exec(text))){ if (m.index > last) frag.appendChild(document.createTextNode(text.slice(last, m.index))); const term=m[1].trim(), heading=m[2].trim(), body=m[3].trim(); const t = insideLink ? document.createElement("span") : document.createElement("button"); if (insideLink){ t.setAttribute("role","button"); t.setAttribute("tabindex","0"); } else { t.type="button"; } t.className="tt-trigger"; t.textContent=term; t.setAttribute("data-tt-h", heading); t.setAttribute("data-tt-b", body); t.setAttribute("aria-haspopup","dialog"); t.setAttribute("aria-expanded","false"); frag.appendChild(t); last = TOKEN_RE.lastIndex; } if (last = 2) return el; el = el.parentElement; } // Fallback: nearest non-inline container el = trigger.parentElement || document.body; while (el && el !== document.body){ const d = getComputedStyle(el).display; if (d !== "inline" && d !== "contents") return el; el = el.parentElement; } return document.body; } // Utility: child of `ancestor` that contains `target` (direct child) function directChildContaining(ancestor, target){ for (const ch of ancestor.children){ if (ch === target || ch.contains(target)) return ch; } return null; } function getElementTarget(e) { // If target is already an Element, use it if (e.target instanceof Element) return e.target; // Otherwise, walk the composed/path for the first Element const path = (typeof e.composedPath === 'function') ? e.composedPath() : []; for (const n of path) if (n instanceof Element) return n; return null; } // ---------------- Dim everything except the trigger branch (sibling branches only) ---------------- function dimAllOtherBranches(container, trigger){ undim(); // clear previous const dimEls = []; const wrappedTexts = []; const pathEls = []; // Build ELEMENT-only path [container -> ... -> trigger] const path = []; for (let el = trigger; el && el !== container; el = el.parentElement) path.push(el); path.push(container); path.reverse(); // At each ancestor level, find the *direct* child that leads to the trigger for (let i = 0; i { if (node.nodeType !== 3) return; // text only if (!node.nodeValue || !node.nodeValue.trim()) return; // If this text node sits inside branchChild, skip if (branchChild && branchChild.contains && branchChild.contains(node)) return; const span = document.createElement("span"); span.style.transition = `opacity ${DIM_EASE_MS}ms ease`; span.style.opacity = String(DIM_OPACITY); span.textContent = node.nodeValue; node.parentNode.replaceChild(span, node); wrappedTexts.push(span); }); // Keep a reference to the path elements (so we can explicitly restore opacity if needed) if (anc && anc.nodeType === 1) pathEls.push(anc); } // Hard-guard: explicitly set opacity:1 on the entire path to neutralize any inherited fade pathEls.forEach(el => { el.style.opacity = "1"; }); dimCtx = { container, dimEls, wrappedTexts, pathEls }; } function undim(){ if (!dimCtx) return; const { dimEls, wrappedTexts, pathEls } = dimCtx; // Animate back dimEls.forEach(el => { el.style.transition = `opacity ${DIM_EASE_MS}ms ease`; el.style.opacity = "1"; // remove inline style after the animation so we don't override site CSS setTimeout(() => { if (el) el.style.opacity = ""; }, DIM_EASE_MS + 50); }); wrappedTexts.forEach(span => { span.style.transition = `opacity ${DIM_EASE_MS}ms ease`; span.style.opacity = "1"; span.addEventListener("transitionend", () => { if (!span.parentNode) return; span.parentNode.replaceChild(document.createTextNode(span.textContent || ""), span); }, { once:true }); }); // Clear hard-guard on path pathEls.forEach(el => { if (el) el.style.opacity = ""; }); dimCtx = null; } // ---------------- Positioning (centered, edge-aware, flip) ---------------- function clamp(v,min,max){ return Math.max(min,Math.min(max,v)); } function measureBubbleForPlacement(){ const wasOpen = bubble.classList.contains("is-open"); if (!wasOpen){ bubble.style.visibility="hidden"; bubble.classList.add("is-open"); } const rect = bubble.getBoundingClientRect(); if (!wasOpen){ bubble.classList.remove("is-open"); bubble.style.visibility=""; } return { w: rect.width, h: rect.height }; } function placeAnchored(trigger){ const vw=innerWidth, vh=innerHeight; const r = trigger.getBoundingClientRect(); const { w, h } = measureBubbleForPlacement(); let left = r.left + (r.width/2) - (w/2); left = clamp(left, EDGE_PADDING, Math.max(EDGE_PADDING, vw - EDGE_PADDING - w)); const topBelow = r.bottom + OFFSET_Y; const spaceBelow = vh - topBelow - EDGE_PADDING; const placeBelow = spaceBelow >= h; let top = placeBelow ? topBelow : (r.top - h - OFFSET_Y); top = clamp(top, EDGE_PADDING, Math.max(EDGE_PADDING, vh - EDGE_PADDING - h)); bubble.style.left = left + "px"; bubble.style.top = top + "px"; const br = bubble.getBoundingClientRect(); if (br.bottom > vh - EDGE_PADDING){ bubble.style.maxHeight = (vh - 2*EDGE_PADDING) + "px"; bubble.style.overflowY = "auto"; } else { bubble.style.maxHeight = "none"; bubble.style.overflowY = "visible"; } } // ---------------- Open / Close (place → fade/scale) ---------------- function animateIn(){ bubble.style.transition = "none"; bubble.style.opacity = "0"; bubble.style.transform = "scale(0.95)"; void bubble.offsetWidth; bubble.style.transition = "opacity .18s ease, transform .18s ease"; bubble.style.opacity = "1"; bubble.style.transform = "scale(1)"; } function animateOut(done){ bubble.style.transition = "opacity .16s ease, transform .16s ease"; bubble.style.opacity = "0"; bubble.style.transform = "scale(0.95)"; const end = () => { bubble.removeEventListener("transitionend", end); done && done(); }; bubble.addEventListener("transitionend", end); setTimeout(end, 260); } function openFromTrigger(trigger){ if (current && current !== trigger) forceClose(); current = trigger; trigger.setAttribute("aria-expanded","true"); elH.textContent = trigger.getAttribute("data-tt-h") || ""; elB.textContent = trigger.getAttribute("data-tt-b") || ""; bubble.classList.add("is-open"); bubble.setAttribute("aria-hidden","false"); placeAnchored(trigger); animateIn(); const container = findTextContainer(trigger); dimAllOtherBranches(container, trigger); hoverCount = 0; cancelCloseTimer(); } function forceClose(){ if (!current) return; bubble.classList.remove("is-open"); bubble.setAttribute("aria-hidden","true"); current.setAttribute("aria-expanded","false"); current = null; undim(); hoverCount = 0; cancelCloseTimer(); } function closeWithAnim(){ if (!current) return; const t = current; animateOut(() => { bubble.classList.remove("is-open"); bubble.setAttribute("aria-hidden","true"); t.setAttribute("aria-expanded","false"); current = null; undim(); }); } function scheduleClose(){ cancelCloseTimer(); closeTimer = setTimeout(() => { if (hoverCount { if (isCoarse()) return; const target = getElementTarget(e); if (!target) return; const t = target.closest(".tt-trigger"); if (!t) return; onZoneEnter(); if (!current || current !== t) openFromTrigger(t); }; const handleLeave = (e) => { if (isCoarse()) return; const target = getElementTarget(e); if (!target) return; const t = target.closest(".tt-trigger"); if (!t) return; onZoneLeave(); }; document.addEventListener("pointerenter", handleEnter, true); document.addEventListener("mouseenter", handleEnter, true); document.addEventListener("pointerleave", handleLeave, true); document.addEventListener("mouseleave", handleLeave, true); // ---------------- Keyboard ---------------- document.addEventListener("focusin", (e) => { if (!e.target) return; const t = e.target.closest(".tt-trigger"); if (t) openFromTrigger(t); }); document.addEventListener("focusout", (e) => { if (!e.target) return; const t = e.target.closest(".tt-trigger"); if (t && current === t) closeWithAnim(); }); // ---------------- Mobile / coarse ---------------- document.addEventListener("pointerdown", (e) => { if (!isCoarse()) return; const t = e.target.closest(".tt-trigger"); if (!t) return; e.preventDefault(); e.stopPropagation(); if (current === t && bubble.classList.contains("is-open")) { closeWithAnim(); return; } openFromTrigger(t); }, true); document.addEventListener("click", (e) => { if (!isCoarse()) return; if (!bubble.classList.contains("is-open")) return; const inBubble = !!e.target.closest(".tt-bubble"); const onTrigger = !!e.target.closest(".tt-trigger"); if (!inBubble && !onTrigger) closeWithAnim(); }, true); // Close button + ESC elClose.addEventListener("click", closeWithAnim); document.addEventListener("keydown", (e) => { if (e.key === "Escape") closeWithAnim(); }); // Reposition on resize/scroll while open const reposition = () => { if (!current) return; placeAnchored(current); }; addEventListener("resize", reposition, { passive: true }); addEventListener("scroll", reposition, { passive: true }); });

How Slack, a Salesforce company, unlocks organizational knowledge with Claude

Try Claude
Contact sales
Watch the video
Play video
Industry:
Software
Company size:
Large
Product:
Claude Platform
Location:
North America
97 minutes per week
Saved by the average user through summarization and recap features
Extensive context window
Claude excels at processing lengthy discussions and providing personalized tone and format for user interactions
Claude Code

Anthropic's agentic coding tool. Claude Code understands your codebase, edits files, runs commands, and helps you ship faster.

Read more
Claude Code
Next

Anthropic's agentic coding tool. Claude Code understands your codebase, edits files, runs commands, and helps you ship faster.

Video caption
Next
Claude Code

Anthropic's agentic coding tool. Claude Code understands your codebase, edits files, runs commands, and helps you ship faster.

Introducing Agent Skills

Claude can now use Skills—folders with instructions, scripts, and resources—to become a specialist at specific tasks when you need it.

Read more
Introducing Agent Skills
Next

Claude can now use Skills—folders with instructions, scripts, and resources—to become a specialist at specific tasks when you need it.

Video caption
Next
Introducing Agent Skills

Claude can now use Skills—folders with instructions, scripts, and resources—to become a specialist at specific tasks when you need it.

Prev
Next

Slack, the agentic work operating system, has teamed up with Anthropic as a key AI collaborator to fundamentally change how teams communicate and access knowledge. By leveraging the advanced capabilities of the Claude models, Slack is delivering a powerful suite of AI features that unlock organizational knowledge, accelerate workflows, and provide measurable impact for enterprise customers.

Through this collaboration, Slack has:

  • Saved the average user 97 minutes per week through summarization and recap features
  • Processed lengthy discussions with extensive context window capabilities
  • Delivered search results that locate relevant content with clear, rapid results
  • Respected content and channel permissions for enterprise security
  • Provided personalized tone and format for user interactions
Slack’s AI delivers prompt conversation summaries of channels and threads, highlighting key decisions and action items, tailored to the user. 

Powering intelligent communication with Claude’s foundational strengths

Slack selected Claude for its exceptional capability in human-like understanding and nuanced conversation analysis. Claude’s models are uniquely equipped to process the billions of messages and files flowing through the Slack platform daily, transforming this wealth of unstructured data into accessible and actionable knowledge.

Technical advantages that power this transformation include:

  • Extensive Context Window: Claude excels at processing lengthy discussions and providing personalized tone and format for user interactions due to its industry-leading, extensive context window capabilities.
  • Safety and Compliance: Anthropic’s commitment to safety and compliance solidified the partnership, ensuring that Slack’s AI solution meets the paramount security and data protection needs of all customers, especially large enterprises.

"Anthropic has been instrumental as we’ve built our AI solution” said Ananya Helmich, VP of Software Engineering at Slack. “The exceptional quality and high performance of Claude models empower us to build AI-driven solutions that truly make a difference for our customers.” 

Robert Ansel, Staff Site Reliability Engineer, said the team uses Claude Code to fix bugs and power teams to move faster.

Transforming how teams work with Slack’s AI features and Claude

Claude models enhance a range of Slack’s AI features, provide intelligent assistance across everyday tasks, and make organizational knowledge readily accessible and actionable. Here's how:

  • AI-Powered Search: Slack users ask questions in natural language to search for relevant information across all content - conversations, threads, and files. Search results locate relevant content and deliver clear, rapid results. 
  • Instant Summaries: Slack’s AI delivers prompt conversation summaries of channels and threads, highlighting key decisions and action items, tailored to the user. 
  • AI-Generated Recaps: This capability streamlines work by prioritizing important messages and unread mentions, providing a concise overview of priority discussions across channels.
  • Productivity-Boosting Tools: Slack’s AI acts as an intelligent assistant, helping users build workflows and create detailed meeting notes from huddles, providing real-time advantages within the platform.

"Slack's close collaboration with Anthropic has helped our Engineering and Product teams accelerate prototyping and model testing," said Samuel Messing, VP of Engineering for search and AI at Slack. "By leveraging Claude's advanced AI capabilities, we've been able to create meaningful improvements across the Slack platform."

By focusing on these deep-seated technical and efficiency improvements, Slack and Anthropic are not just accelerating workflows—they are co-inventing the future of work.

"Slack's close collaboration with Anthropic has helped our Engineering and Product teams accelerate prototyping and model testing."
Samuel Messing
VP of Engineering, Slack

Next

Video caption
Next

Prev
Next