Webflow Localisation Anchor link fix
Why this is needed
When Webflow Localization is on, links like /#why can get rewritten to /de/#why. That looks fine, but Webflow’s built-in smooth scroll usually triggers only when the link is interpreted as a same-page anchor. After localization, some anchors behave like full page loads (no animation), and language switchers can also get unintentionally rewritten.
What the script does
- Detects secondary locale from the first URL segment (e.g., /de/, /en/).
 - Normalizes internal links that are missing the current locale (adds /de/...).
 - Preserves smooth scroll for same-page anchors by:
- Ensuring the final href is /<locale>/<path>/#id (with the slash before #), and
 - Providing a click handler that smoothly scrolls even if Webflow doesn’t.
 
 - Skips:
- Language switchers (<a hreflang="…">) and any link with data-flow-locale-skip.
 - External links and common asset/file extensions.
 
 - Keeps your markup style (absolute vs relative) when updating href.
 - Re-initializes Webflow Interactions (IX2) after updates so animations continue to work.
 
How to use
- Preferred placement: Webflow → Page Settings → Before </body>.
 - Alternative: inside <head> (it waits for DOMContentLoaded, so it’s safe).
 
The code (clean version)
1<script>
2// Component by Flowing.to
3// Locale-aware link normalizer for secondary locales + smooth-scroll fix + IX2 reinit.
4
5document.addEventListener('DOMContentLoaded', function () {
6  // --- Locale ---------------------------------------------------------------
7  const LOCALE_RE = /^[a-z]{2}(?:-[a-z]{2})?$/i;
8  const { location, document } = window;
9
10  const extractLocale = (p) => {
11    const s = p.split('/').filter(Boolean)[0];
12    return LOCALE_RE.test(s) ? s : null;
13  };
14  const currentLocale = extractLocale(location.pathname);
15  const isPrimary = !currentLocale;
16
17  // --- Small helpers --------------------------------------------------------
18  const isInternal = (u) => u.origin === location.origin;
19
20  const isSkippableHref = (href) => {
21    if (!href) return true;
22    const h = href.trim().toLowerCase();
23    return h === '#' ||
24           h.startsWith('mailto:') ||
25           h.startsWith('tel:') ||
26           h.startsWith('javascript:') ||
27           h.startsWith('data:') ||
28           h.startsWith('blob:');
29  };
30
31  const BLOCK_EXTS = new Set(['pdf','jpg','jpeg','png','gif','svg','webp','ico','mp4','webm','mov','zip','rar','7z','css','js','woff','woff2','ttf','eot','map']);
32  const isAssetPath = (pathname) => {
33    const last = (pathname.split('/').pop() || '');
34    const i = last.lastIndexOf('.');
35    return i > -1 && BLOCK_EXTS.has(last.slice(i + 1).toLowerCase());
36  };
37
38  const norm = (p) => (!p || p === '/') ? '/' : (p.endsWith('/') ? p.slice(0, -1) : p);
39  const samePath = (a, b) => norm(a) === norm(b);
40  const ensureLeadingSlash = (p) => (p.startsWith('/') ? p : '/' + p);
41  const withTrailingSlash = (p) => (p.endsWith('/') ? p : p + '/');
42
43  // --- Localize links only on secondary locales ----------------------------
44  if (!isPrimary) {
45    document.querySelectorAll('a[href]:not([hreflang]):not([data-flow-locale-skip])')
46      .forEach(a => {
47        const raw = a.getAttribute('href');
48        if (isSkippableHref(raw)) return;
49
50        let url;
51        try { url = new URL(raw, location.href); } catch { return; }
52        if (!isInternal(url)) return;
53        if (isAssetPath(url.pathname)) return;
54
55        // Already localized? leave it.
56        const firstSeg = url.pathname.split('/').filter(Boolean)[0];
57        if (firstSeg && LOCALE_RE.test(firstSeg)) return;
58
59        // Inject current locale
60        url.pathname = `/${currentLocale}${ensureLeadingSlash(url.pathname)}`;
61
62        // Same-page anchor? ensure "/de/.../#id" (slash before hash)
63        if (samePath(url.pathname, location.pathname) && url.hash) {
64          a.setAttribute('href', withTrailingSlash(norm(location.pathname)) + url.hash);
65          return;
66        }
67
68        // Keep original absolute/relative style
69        if (/^https?:\/\//i.test(raw)) {
70          a.setAttribute('href', url.href);
71        } else {
72          a.setAttribute('href', url.pathname + url.search + url.hash);
73        }
74      });
75  }
76
77  // --- Smooth-scroll safety net for same-page anchors ----------------------
78  // (Covers cases where Webflow doesn't auto-smooth after our rewrites.)
79  document.addEventListener('click', function (e) {
80    const a = e.target.closest('a[href]');
81    if (!a || a.hasAttribute('hreflang') || a.hasAttribute('data-flow-locale-skip')) return;
82
83    const href = a.getAttribute('href');
84    if (!href) return;
85
86    let u;
87    try { u = new URL(href, location.href); } catch { return; }
88    if (u.origin !== location.origin || !u.hash) return;
89    if (!samePath(u.pathname || '/', location.pathname || '/')) return;
90
91    const id = decodeURIComponent(u.hash.slice(1));
92    if (!id) return;
93
94    const target = document.getElementById(id) || document.querySelector(`[name="${CSS.escape(id)}"]`);
95    if (!target) return;
96
97    e.preventDefault();
98    target.scrollIntoView({ behavior: 'smooth', block: 'start' });
99    history.pushState(null, '', withTrailingSlash(norm(location.pathname)) + u.hash);
100  }, { capture: true });
101
102  // --- Re-init Webflow Interactions after href edits -----------------------
103  try {
104    if (window.Webflow && typeof window.Webflow.require === 'function') {
105      window.Webflow.ready && window.Webflow.ready();
106      window.Webflow.require('ix2').init();
107    }
108  } catch (e) {
109    console.warn('[Flowing] IX2 re-init failed:', e);
110  }
111});
112</script>Options & notes
- Exclude any link from rewriting: add data-flow-locale-skip to the <a>.
 - Custom locales (e.g., en-US): already supported by the regex.
 - Assets list: extend BLOCK_EXTS if you host other file types.
 - Primary locale (no /en/ in path): script does nothing to links there.
 
You can copy-paste this component directly into your Webflow project and style it however you want.
[ag-0-d-This is the description]
[ag-0-a-name = value]
[ag-0-a-name = value]- This is the description[li-a-name = value]Click to Copy[li-a-name = value]
 - This is the description[li-a-name = value][li-a-name = value]
 - This is the description[li-a-name = value][li-a-name = value]
 
Quick Setup:
You can copy-paste this component directly into your Webflow project and style it however you want.
[c-Final - First Bento Grid]
Required Attributes:
- this is the head. should it be the first item or should it be the first heading before the list?
 - data-flow = card: Defines the card element. The glow is inside this div.
 - data-flow-color-border = #your-color: Sets the border glow color. Accepts CSS variables, functions, or static color values.
 - data-flow-color-card = #your-color: Sets the inner glow color. Accepts CSS variables, functions, or static color values.
 
Optional Settings:
Use variables and the color-mix function. You can set the card’s inner glow to something like: [a-data-flow-color-card = "color-mix(in srgb, var(--pink) 20%, transparent)"]. Here we are using a color variable, which can be the same as the border  [a-data-flow-color = "transparent)"] color, but set it to 20% opacity with the color-mix function.
In the code, there are two default values that you can change if you want.










