A horizontal scrollable menu in Elementor sounds like a five-minute job, right up until the menu items squash into unreadable stubs instead of sliding off the edge. That is the bit most tutorials skip. Elementor’s own stylesheet sets flex-wrap: wrap on the menu list and lets every item shrink, so flipping to nowrap on its own does almost nothing. Here is the CSS that actually holds, where to paste it, how to check it on a real phone, and what it costs you.
Quick verdict
- The one rule that matters:
flex: 0 0 autoon the menu list items. Without it they compress instead of overflowing, and nothing scrolls. - Widget: Elementor Pro’s Nav Menu widget, set to the Horizontal layout. On sites with the Menu experiment switched on it answers to WordPress Menu instead.
- Free route: the CSS is builder-agnostic. Any horizontal list of links takes the same treatment; only the class names change.
- Skip it if your menu has dropdown submenus. A scroll container clips them, and no amount of CSS gets that back.
- Our call: excellent as a category strip on a content site. A poor choice as the only navigation a visitor has.
What the pattern looks like
News sites have leaned on this for years: a single row of category links under the masthead that you swipe through with a thumb. It buys you fifteen navigation targets in the vertical space of one, and it puts them on screen instead of behind a hamburger tap.


Before you start
Three things decide whether the CSS below lands on the first try.
- The right widget. The Nav Menu widget is Pro-only, so this needs Elementor Pro. If you have activated the Containers, Nested Elements and Menu experiments, Elementor’s docs note that this replaces Nav Menu with two widgets: WordPress Menu, which behaves the same and outputs the same markup, and Menu, which is the mega-menu builder and uses different markup entirely. This CSS targets the first one.
- Layout set to Horizontal. The vertical layout produces a different class on the wrapper and the rules will not apply.
- Your real breakpoint. Elementor’s default breakpoints are a max-width of 767px for mobile and 1024px for tablet. If you edited them under Site Settings → Layout → Breakpoints, use your number, not ours.
Build it: six steps
- Open the header template. Templates → Theme Builder → Header, then edit the header you are already using. Add a container below your logo row for the strip to live in. If you want this row on more than one template, build it once as a global widget you can reuse across Elementor templates.
- Drop in the Nav Menu widget and pick the menu. A menu built from your post categories is the usual choice, which is why this pairs well with a custom single post layout. Set Layout to Horizontal.
- Restrict it to mobile. Advanced → Responsive, switch on Hide On Desktop and Hide On Tablet. Elementor applies its own
elementor-hidden-desktopandelementor-hidden-tabletclasses, which are keyed to the same 767px and 1024px boundaries. Leave both off if you want the strip on every screen size. - Give it a class. Advanced → Layout → CSS Classes, type
smw-scroll-nav. No leading dot. The field wants a class name, not a selector, and a stray dot is a common reason this tutorial fails. - Paste the CSS from the next section into Appearance → Customize → Additional CSS. That location works on every plan and every theme, and it loads after Elementor’s own stylesheet.
- Verify on hardware, not in the editor preview. Details below.
The CSS
The scroll container is the ul.elementor-nav-menu that the widget outputs. The selector below is deliberately one class heavier than Elementor’s own rule so it wins on specificity rather than on load order, which means it keeps working if you later move the CSS somewhere that loads earlier.
/* Horizontal scrolling menu — Elementor Nav Menu widget */
@media (max-width: 767px) {
/* The list is the scroll container. */
.smw-scroll-nav.elementor-widget .elementor-nav-menu {
display: flex;
flex-wrap: nowrap; /* Elementor sets wrap; override it */
overflow-x: auto;
overflow-y: hidden;
overscroll-behavior-x: contain; /* stop the swipe chaining to the page */
scroll-padding-inline: 16px; /* breathing room when focus scrolls in */
padding-block: 4px; /* so focus outlines are not clipped */
gap: 8px;
}
/* The rule that actually makes it scroll. Elementor sets
display:flex on each list item, so by default they shrink
to fit rather than pushing past the right edge. */
.smw-scroll-nav.elementor-widget .elementor-nav-menu > li {
flex: 0 0 auto;
}
/* Margin, not padding. End padding on a horizontal flex scroll
container is dropped from the scrollable area. */
.smw-scroll-nav.elementor-widget .elementor-nav-menu > li:first-child {
margin-inline-start: 16px;
}
.smw-scroll-nav.elementor-widget .elementor-nav-menu > li:last-child {
margin-inline-end: 16px;
}
/* Insurance, in case a theme reset undoes Elementor's own rule. */
.smw-scroll-nav.elementor-widget .elementor-nav-menu > li > a.elementor-item {
white-space: nowrap;
}
}
That is the whole mechanism. Everything after this is styling.
Optional: pill buttons
The line-height and padding here are set explicitly so the maths is yours to check: 10px top, 20px line, 10px bottom, plus a 1px border top and bottom, gives a 42px tap target, comfortably past the 24 by 24 CSS pixel floor in WCAG 2.2 SC 2.5.8, Target Size (Minimum).
@media (max-width: 767px) {
.smw-scroll-nav.elementor-widget .elementor-nav-menu > li > a.elementor-item {
background: #fff;
border: 1px solid #e3e5ea;
border-radius: 999px;
padding: 10px 16px;
line-height: 20px; /* 10 + 20 + 10 + 2px border = 42px tall */
font-size: 14px;
}
.smw-scroll-nav.elementor-widget .elementor-nav-menu > li > a.elementor-item.elementor-item-active {
background: #111;
border-color: #111;
color: #fff;
}
}

Optional: hide the scrollbar
Read the accessibility section before you use this. If you still want it, note that the scrollbar here is horizontal, so the WebKit pseudo-element needs a height of zero, not a width. The standard property has been Baseline since December 2024 and covers current browsers on its own; the second rule is only there for older Safari.
@media (max-width: 767px) {
.smw-scroll-nav.elementor-widget .elementor-nav-menu {
scrollbar-width: none;
}
.smw-scroll-nav.elementor-widget .elementor-nav-menu::-webkit-scrollbar {
height: 0;
}
}
Verify it properly
Elementor’s responsive preview is a resized desktop viewport. It will not show you momentum scrolling, it renders scrollbars the way your desktop OS does, and it never reproduces a phone held sideways. Load the actual URL on an actual handset and work through these.
- Swipe the strip. Items should slide sideways at their natural width. If they are squashed and the text is clipped,
flex: 0 0 autois not applying. Inspect a list item and check whether your rule is being crossed out. - Rotate the phone sideways. Most handsets report more than 767px wide in that orientation, so a strip hidden on tablet will vanish and your tablet layout appears instead. Decide whether that is acceptable before a client finds it.
- Check the page itself does not scroll sideways. In DevTools at a 375px viewport, run
document.documentElement.scrollWidth > document.documentElement.clientWidth. It must returnfalse. If it returns true, your strip is overflowing its container rather than scrolling inside it, usually because a parent hasoverflow: visibleand no width constraint. - Tab through it at that same narrow width. Each link should take focus in order and the browser should scroll it into view. If focus rings are sliced off top and bottom, raise the
padding-blockvalue.
What breaks
Dropdown submenus. The Nav Menu widget positions submenus absolutely inside the list. Turning that list into a scroll container clips them to the strip, so a submenu appears as a sliver or not at all. There is no CSS fix worth having. Build a second, flat menu for the scroll row and keep the nested one in a burger, or move the nested items into an Elementor popup used as an off-canvas menu.
Trailing space disappearing. If you put padding-inline-end on the scroll container instead of a margin on the last item, the last pill sits flush against the edge when you scroll to the end. This is long-standing flexbox and padding behaviour, not an Elementor bug, and the margin approach in the CSS above sidesteps it.
Sticky headers. A horizontal scroller inside a sticky header is fine, but stack them carefully: the sticky wrapper needs its own height or the strip’s scrollbar can push it. Worth reading alongside a blurred animated sticky header in Elementor if you are combining the two.
Showing it in the wrong places. A category strip on a checkout page is noise. Conditional display is easier with a dynamic visibility plugin than with duplicate header templates.
What most tutorials get wrong
Four errors get copied from post to post, including from the 2022 version of this one.
flex-wrap: nowrapon its own. Flex items still shrink. You get one squashed row that scrolls nowhere. The missing piece is alwaysflex: 0 0 auto.::-webkit-scrollbar { width: 0 }. Wrong axis. A horizontal scrollbar has height, not width, so this hides nothing.-webkit-overflow-scrolling: touch. Safari on iOS 13 made momentum scrolling the default for overflow containers and the property is deprecated. It still parses, which is exactly why it keeps surviving copy-paste. Delete it, along with-ms-overflow-style, which only ever spoke to Internet Explorer.max-width: 768px. Off by one against Elementor’s own 767px mobile boundary. At exactly 768px you get the tablet layout with the mobile scroll rules layered on top, which is a strange bug to debug six months later.
The accessibility catch
Horizontal scroll containers are not an automatic audit failure, but three specific things trip them up.
Hiding the scrollbar removes the only cue. MDN is blunt about it: avoid none, because hiding a scrollbar negatively impacts accessibility. On a touch device the scrollbar was never visible anyway, so the honest substitute is layout. Size the strip so the last item is deliberately half cut off. A sliced pill says “there is more here” better than any arrow icon.
Keyboard access is fine here, but for a reason. Chrome made scroll containers keyboard-focusable by default, and that behaviour applies only to scrollers with no focusable children. A menu is a list of links, so the container is skipped and Tab walks the links instead, with the browser scrolling each into view. That works. It stops working the moment you build the same strip out of non-focusable content such as plain text chips, at which point you owe it a tabindex="0" and a real aria-label.
Reflow is about the page, not the strip. WCAG SC 1.4.10 Reflow asks that content work at 320 CSS pixels without scrolling in two dimensions. A self-contained scroller inside a page that still scrolls vertically is not what that criterion is aimed at. What does fail is a strip that overflows its parent and drags the whole document sideways, which is exactly the check in step three above. The widget already outputs a <nav> with an aria-label of Menu; if the page has a second nav, give them distinguishable labels so a screen reader user can tell them apart.
Should you use this at all?
- Content site, eight to twenty flat categories: yes. This is the case the pattern was invented for, and it fits naturally on top of a blog built in Elementor.
- Fewer than five items: no. They already fit on one line. You are adding a scroll container for nothing.
- Store with nested product categories: no. Off-canvas, every time. Nesting and scroll containers do not mix.
- Your only navigation: no. Anything past the right edge is invisible on first paint, so run this as a secondary layer above a normal menu, never instead of one.
- Not on Elementor: the CSS transfers unchanged apart from selectors. Bricks and the other visual page builders for WordPress all output a list of links, which is all this needs. If you would rather not touch CSS at all, several Elementor addon packs ship a menu widget with a scroll toggle built in.
Frequently Asked Questions
Why do my menu items squash instead of scrolling?
Elementor styles the menu list with flex-wrap: wrap and leaves every item free to shrink. Switching the list to nowrap does not remove that shrink behaviour, so the items compress and the text clips. Add flex: 0 0 auto to the list items and they will overflow, which is what creates the scroll.
Do I need Elementor Pro for this?
For the Nav Menu widget, yes, since it is a Pro widget. The scrolling itself is plain CSS with no dependency on Elementor, so a free site can apply the same three rules to a block theme navigation block or an addon menu widget. Only the class names in the selectors change.
Can I keep dropdown submenus in a scrolling menu?
Not reliably. The widget positions submenus absolutely inside the menu list, and overflow-x: auto turns that list into a scroll container which clips them. Keep parent items that have children out of the strip, and put the nested navigation in a burger or off-canvas panel instead.
Should I hide the scrollbar?
Usually not. MDN warns against the none value because hiding a scrollbar removes the only visual signal that more content exists. If the design demands it, size the row so the last item is half cut off at the edge. That partial item does the same job without removing anything.
Which breakpoint value should the media query use?
Use 767px, not 768px. Elementor’s default mobile breakpoint is a max-width of 767px and tablet is 1024px, so a 768px query overlaps the tablet layout by a pixel. If you changed the values under Site Settings, match your own numbers rather than the defaults.
Is -webkit-overflow-scrolling: touch still needed?
No. Safari on iOS 13 and later applies momentum scrolling to overflow containers by default, and the property is deprecated. It still parses without error, which is why it keeps surviving in copied snippets, but it changes nothing on any current device. Remove it.
Will a horizontal scrolling menu fail an accessibility audit?
Not by itself. WCAG SC 1.4.10 Reflow targets pages that need scrolling in two dimensions at 320 pixels, not a self-contained scroller inside one. The real failures are hidden scrollbars, focus outlines clipped by the overflow, and tap targets under 24 by 24 CSS pixels.
Where should the CSS go?
Appearance → Customize → Additional CSS is the safest place. It works on every plan, survives Elementor updates and loads after the plugin stylesheet. Elementor Pro also offers a Custom CSS field per widget and site-wide in Site Settings. Pick one location and keep all of it there.
Our call
Build it if you run a content site with a flat category structure and you want those categories on screen rather than behind a tap. Three rules do the work, the whole thing is about twenty lines of CSS, and it degrades to a normal wrapping menu if the CSS ever fails to load. Skip it if your navigation has nesting, if you have fewer than five items, or if this would be the only way to move around the site. And leave the scrollbar alone, or leave a pill half cut off at the edge in its place. The strip is worthless if nobody realises it moves.
Technical details verified August 2026 against Elementor’s documentation, MDN and the W3C Understanding documents linked above.




thats cool. Do you know a way to scroll automatically to the selected item?
Thank you so much Alex. Yes, you can automatically scroll to the selected item by using selectors in the links for the menu items.
Kindly let me know if it is something you were looking for.
Thank you so much!
Please provide a detailed explanation.
Hey, please join our community and share what you exactly want to achieve, rest assured you will get the answers. Do you want to set it on a specific element on load?
Thank you so much, I thinked this was more complicated to do than really is
You’re most welcome Alecsander. Thanks for your comment. 🙂
Is there a way to make the submenus here to also work, since it is not functioning on mobile, when flex-wrap is set to nowrap. Submenus then appear as a vertical scroll. Is there a way to make the submenu go over the border of the menu and expand down?