Radial slider
A slider on a wheel. The cards sit on the rim of a great wheel that lies flat, facing the page, its hub far under the foot of the section: what shows is the top of the rim, an arc of cards that lean, sink and fade to each side.
Documentation
-
Copy to Webflow
Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: Webflow removes any font your site has not installed. -
Add custom CSS
Custom CSS in WebflowThis CSS already ships inside the Webflow embed, so a pasted section needs nothing added. Paste it yourself, in the page or the site custom code, only if the effect runs on several pages. The tutorial explains where.
See the tutorialGive the cards a width: the whole wheel is built from the box of a card. Leave the section room under the card at the top, where the side cards sink, and set no transform or opacity on the cards themselves: the script writes both. -
Add custom JS
Custom JavaScript in WebflowThis script already ships inside the Webflow embed, settings block included. You paste it yourself, before the closing body tag of the page or the site custom code, only when the effect has to run on several pages, and the tutorial says how to choose.
See the tutorial -
Tune it
How to add a custom attribute in WebflowA custom attribute is a pair, a name and a value, typed in the Settings panel of the element you selected, under Custom attributes. The name is what the script looks for, the value is what it reads. The tutorial shows the panel.
See the tutorialCustom attributesSelect the section on the canvas and open the Settings panel. Under Custom attributes, add a pair: the name on the left, the value on the right.Custom attribute What it does data-radial-slider Marks the section that holds the wheel. It takes no value: leave the value field empty. That section is what the engine mounts on, what carries the settings and the states, what cuts the cards that sink past its edges, and what it looks for the wheel, the counter, the caption box and the buttons in. Without it on any section of the page, the embed marks the section holding each wheel (data-radial-slider-wheel). data-radial-slider-wheel Marks the box that holds the cards, the top of the rim. Without it the parent of the first marked card is taken; with neither, nothing is mounted and the console says so. [ Required ] data-radial-slider-card Marks one card, a child of the wheel. Two at least, and as many as you like: the wheel is endless when they cover its arc and one card more, ten with the defaults, and keeps two ends with fewer. Without it on any of them the engine takes the wheel's own children as the cards. [ Optional ] data-radial-slider-stage Marks the box the hand grabs, which also takes the mouse wheel and the keyboard focus. Without it the parent of the wheel is taken. [ Optional ] data-radial-slider-caption Marks the caption of a card, inside it. With the script it is hidden in the card and shown in the display box when the card is at the top. Without it the alt of the card's picture is used. [ Optional ] data-radial-slider-display Marks the box that shows the caption of the card at the top, which comes out of a mask at each change. Without it no caption is shown. [ Optional ] data-radial-slider-current Marks the number of the card at the top. The engine fills it with a reel that rolls as the wheel turns. Without it there is no current number. [ Optional ] data-radial-slider-total Marks the total of the counter, which the engine writes as the card count. Without it there is no total. [ Optional ] data-radial-slider-prev Marks a button that steps the wheel one card back. Without it the drag, the mouse wheel and the arrow keys still do. [ Optional ] data-radial-slider-next Marks a button that steps the wheel one card further. Without it the drag, the mouse wheel and the arrow keys still do. [ Optional ] data-radial-slider-state Written by the engine on the section: ready, or still under reduced motion. Never written by hand; the stylesheet reads it to pile the cards at the top of the wheel, cut the section and show the hand. [ Optional ] data-radial-slider-dragging Written by the engine on the section while a drag runs. Never written by hand; the stylesheet reads it for the closed hand. [ Optional ] data-radial-slider-endless Written by the engine on the section while the wheel goes round without end, and absent while it has a first and a last card. Never written by hand; a rule of the page may read it. [ Optional ] data-radial-slider-active Written by the engine on the card at the top. Never written by hand; a rule of the page may read it. [ Optional ] SettingsEvery setting is a custom attribute too, added the same way and on the same section. An attribute always wins over the defaults written in the code.Attribute Default What it is data-radial-slider-color #f4ece0 Colour of the current number of the counter and of the caption, the cream in the dark look. Options: any CSS colour; without the setting, --radial-slider-color on the section takes over. data-radial-slider-radius 6 Radius of the wheel, from its hub to the middle of a card, in card widths. data-radial-slider-gap 0.1 Space left between two cards where they are closest, at their feet, as a share of the card width. data-radial-slider-arc 50 Half opening of the arc the cards show on, in degrees from the top; a card reaching it is taken out. data-radial-slider-fade 1 How far a card has faded when it reaches the end of the arc, 0 to 1; it fades as the square of its way there. data-radial-slider-loop 1 Whether the wheel is endless when its cards cover the arc and one card more. Options: 1 lets it go round without end when the cards allow it; 0 always keeps a first and a last card, with a soft stop at each. data-radial-slider-friction 0.965 Share of its speed a spinning wheel keeps from one frame to the next, at 60 frames a second. data-radial-slider-snap 140 Stiffness of the spring that docks a card and that steps the wheel from the keys, the buttons and a click. data-radial-slider-autoplay 0 Time between two cards when the wheel turns by itself, in seconds.
Two files and their pictures (12), no build step.
It runs in the browser only. Load it with a script tag in plain HTML, in a
client-side script in Astro, never in the frontmatter. In React, call
RadialSlider.mount(ref.current) in useEffect and
destroy() in its cleanup.
-
Tune it, either way
Per element with an attribute, or once for the whole site by editingDEFAULTSat the top of the file.Attribute Default What it is Lower Higher data-radial-slider-color #f4ece0 Colour of the current number of the counter and of the caption, the cream in the dark look. Options: any CSS colour; without the setting, --radial-slider-color on the section takes over. data-radial-slider-radius 6 Radius of the wheel, from its hub to the middle of a card, in card widths. A small wheel: a tight arc, the side cards lean hard and sink fast A great wheel: a shallow arc, close to a straight row, and more cards needed for an endless one data-radial-slider-gap 0.1 Space left between two cards where they are closest, at their feet, as a share of the card width. At 0 the feet of the cards touch Cards set well apart, fewer of them on screen data-radial-slider-arc 50 Half opening of the arc the cards show on, in degrees from the top; a card reaching it is taken out. A narrow window on the top of the wheel, which fewer cards are enough to make endless Cards shown far down the sides; the wheel needs more cards to be endless data-radial-slider-fade 1 How far a card has faded when it reaches the end of the arc, 0 to 1; it fades as the square of its way there. At 0 every card stays at full ink until it is taken out At 1 a card has gone by the time it reaches the end of the arc data-radial-slider-loop 1 Whether the wheel is endless when its cards cover the arc and one card more. Options: 1 lets it go round without end when the cards allow it; 0 always keeps a first and a last card, with a soft stop at each. data-radial-slider-friction 0.965 Share of its speed a spinning wheel keeps from one frame to the next, at 60 frames a second. A heavy wheel that stops soon after the hand lets go A light wheel that spins on for several cards data-radial-slider-snap 140 Stiffness of the spring that docks a card and that steps the wheel from the keys, the buttons and a click. A lazy, soft dock A quick, firm dock; past 400 it reads as a click data-radial-slider-autoplay 0 Time between two cards when the wheel turns by itself, in seconds. At 0 the wheel never turns by itself A slower slideshow -
Drive it from JavaScript
When a button of your own has to turn the wheel, when the cards change size after load, or when the page reacts to the card at the top.const element = document.querySelector('[data-radial-slider]'); element.addEventListener('radialslider:change', (e) => { console.log(e.detail); }); const wheel = RadialSlider.mount(element); // the section auto() mounted, or a new one wheel.select(3); // throws the wheel so that it docks on the fourth card wheel.next(); // one card further, on the spring element.addEventListener('radialslider:change', (e) => { console.log(e.detail.index); // the card at the top }); // When the slider leaves the page: RadialSlider.destroy(element); // gives back the markup as it was
-
Fit it to your page
- Mark the parts.
data-radial-slideron the section, then inside it-wheelon the box that holds the cards and-cardon each card, a child of the wheel. Two cards at least. Optional:-stageon the box the hand grabs (without it, the parent of the wheel),-captionon the caption inside each card,-displayon the box that shows the caption of the card at the top,-currentand-totalon the two numbers of the counter,-prevand-nexton two buttons. A wheel with no card marked takes its own children as the cards. - Any number of cards. The engine counts them. The step between two cards comes from the box of a card, the
radiusand thegap, not from their number: adding cards makes the row longer, not the cards closer. The wheel is endless when the row covers the arc and one card more, twicearcplus one step: ten cards with the defaults and the cards of the preview. With fewer it keeps a first and a last card, the hand pulling a little past each and a throw sinking softly into them. To make a short row endless, narrow thearc. - The box of a card is the measure of the whole wheel. The radius is
radiuscard widths, so the wheel grows and shrinks with the card and the arc keeps its shape at every size. Give the card a fluid width and the wheel follows it: nothing else is sized. The hub sits one radius under the middle of the card at the top, so leave the section room under that card, where the side cards sink. - The section cuts what sinks past it. Once mounted, the section has
overflow: clip, so the side cards never widen the page or lie over the next section. - The caption of a card is the content of its
-captionelement, or thealtof its picture when there is none. With the script it is hidden in the card and shown in the-displaybox. It may hold several lines: the preview has a name and a note. - One setting for every wheel of the page, without opening the file:
window.RadialSliderSettings = { radius: 8 }in a script placed beforeradial-slider.js. Three levels, least specific first:DEFAULTS, then that object, then adata-radial-slider-*attribute on the section. - Inputs. Mouse and finger through Pointer Events: the stage has
touch-action: pan-y, so a vertical swipe scrolls the page and a sideways one turns the wheel. The wheel turns by the angle the hand travels round the hub, so the card under the hand stays under it. A press that travels less than 6 pixels is a click: the card at the top keeps it, so it can be a link, and a card that is not at the top comes to the top instead. A slow drag let go a little way towards the next card goes to that card. A trackpad swiped sideways, or a mouse wheel with shift, pushes the wheel; a plain vertical wheel is left to the page whenever the page has somewhere to scroll, and turns the wheel on a page that has not. The arrow keys step one card, Home and End go to the first and the last: they are heard when the focus is in the section, and also when nothing on the page has the focus and the wheel is on screen. - States, written by the engine on the section:
data-radial-slider-stateisready, orstillunder reduced motion,data-radial-slider-draggingis there while a drag runs, anddata-radial-slider-endlesswhile the wheel has no ends. The card at the top carriesdata-radial-slider-active. - Reduced motion: the wheel stands as it is and nothing glides. A swipe, a wheel notch, a key, a button or a click steps one card at once, the counter and the caption change without rolling, and
autoplayis off. - From JavaScript:
RadialSlider.mount(el, overrides)returns the instance:element,settings,cards,index()(the card at the top),rotation()(degrees),speed()(degrees per second),step()(degrees between two cards),endless(),phase(),isRunning(),go(i)(card i to the top on the spring),next(),prev(),select(i)(throws the wheel so that its glide docks on card i),refresh()(measures again) anddestroy().destroy()takes off every listener and timer, the counter and the caption it built, the states, the marks it added and every style it wrote, so the markup is as it was.RadialSlider.destroy(el),RadialSlider.refresh(el),RadialSlider.select(el, i),RadialSlider.auto(root)andRadialSlider.defaultscomplete it. - Events, both bubbling,
detail{ element, index, card, cards }:radialslider:changeeach time another card comes to the top, once at mount for the first, andradialslider:settleeach time the wheel comes to rest on a card. - The preview ships whole.
snippet.html, the last part ofradial-slider.css, after the linelook, left out of the Webflow Embed, and the pictures ofimages/are the preview, in Geist and Geist Mono, loaded by the font tag of the Code tab. Theradial-slider-*classes are never read by the engine: on cards of your own, keep your classes, add the attributes, and drop that last part of the file and the font tag. - On Webflow, add the fonts first. Add Geist and Geist Mono to your site's fonts (Site settings, Fonts, Google Fonts) before pasting: the paste names them, and the Designer drops a font the site does not have.
- Mark the parts.
-
Avoid the pitfalls
- The cards need a width, and one size. A card with no width of its own takes the width of its content, and the wheel is built from the widest and the tallest card. Cards of different heights are centred on the rim.
- Leave the cards their transform and their opacity. The engine writes
transform,transform-origin,opacityandvisibilityon each card. A rule of the page that sets one of them on the card is overwritten; put a hover effect on something inside the card. - A wheel that has ends where an endless one was wanted has too few cards for its arc. Read
data-radial-slider-endlesson the section, orendless(): add cards, or lowerarcuntil twice the arc plus one step fits in the row. - The section clips, so nothing of the wheel shows outside it. A short section cuts the card at the top itself. Give the section the height of the card plus the room it needs over and under it.
- **Settings handed to
mount()after the page loaded are dropped.**auto()mounts on DOM ready, andmount()on a section already mounted returns the running instance. A page-wide block goes inwindow.RadialSliderSettings, whichauto()reads itself. - Two wheels on one screen both hear the arrow keys when nothing has the focus. Focus one of them, by a click or by Tab, and only that one turns.
- Cards added or removed after mount are not seen: call
RadialSlider.destroy(el)thenRadialSlider.mount(el).
One click on Copy the AI prompt copies everything an assistant needs to build this effect: the complete code, the markup, the dependency, every setting and every pitfall.
What it does
Radial slider is a scroll animation for Webflow and vanilla JavaScript, with no library. Also called radial cards slider, circular carousel or arc slider.
A slider on a wheel. The cards sit on the rim of a great wheel that lies flat, facing the page, its hub far under the foot of the section: what shows is the top of the rim, an arc of cards that lean, sink and fade to each side. The hand grabs the wheel, with the mouse or a finger, and throws it: the wheel runs on with the speed it was given, loses it to friction with no notch as the cards go by, and docks on a card, a soft spring taking it for the last degrees. Over the wheel, the number of the card at the top rolls on a reel geared to it, and its caption comes out of a mask as the card comes in. A mouse wheel pushes it, the arrow keys and two buttons step it card by card, and a click on a card that is not at the top brings it there. The engine counts the cards of the markup: the wheel is endless when they cover its arc, and keeps two soft ends when they do not. Under reduced motion the wheel stands still and every input steps one card at once. No library: Pointer Events and one rotation per card, on a clock that sleeps at rest. Pattern type radial slider, circular carousel, arc slider, wheel carousel.
Updated
Questions
Mark three levels with custom attributes: data-radial-slider on the section, data-radial-slider-wheel on the box that holds the cards, and data-radial-slider-card on each card. Settings go on the section, for instance data-radial-slider-radius="8" for a shallower arc.
Enough to cover the visible arc and one card more: ten with the default settings and the cards of the preview. The engine counts the cards of the markup and works it out itself; with fewer, the wheel keeps a first and a last card with a soft stop at each. To loop a short row, lower data-radial-slider-arc rather than duplicating cards.
No, it loads no library. The drag is read through Pointer Events as an angle round the hub of the wheel, and each card gets one rotation per frame, on a clock that sleeps at rest. The momentum after a throw and the spring that docks a card are computed by the engine.
With data-radial-slider-radius, the radius of the wheel in card widths, 6 by default. A lower value gives a tight arc whose side cards lean and sink fast, a higher one a shallow arc close to a straight row. The wheel is sized from the card, so a fluid card width keeps the same curve at every screen size.
No. The stage has touch-action: pan-y, so a vertical swipe scrolls the page and a sideways one turns the wheel. A plain vertical mouse wheel is also left to the page whenever the page has somewhere to scroll, and the arrow keys step the wheel one card at a time.