Gesplitste knop met menu New
A primary action with a caret beside it for the variants, such as Send next to "Schedule" and "Save as draft". The menu follows the WAI-ARIA menu pattern: arrows, Home/End, Escape back to the button, focus goes to the first item. The menu opens upwards so it fits in tight cards. For quote and invoice screens, CMS publishing and anywhere with one normal and a few special actions.
Badkamer Delft, € 12.480
How to use it
- Paste the HTML where the buttons should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Gesplitste knop met menu · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="ksp">
<div class="ksp__box">
<div class="ksp__split">
<button class="ksp__main" type="button">Offerte versturen</button>
<button class="ksp__more" type="button" aria-haspopup="menu" aria-expanded="false" aria-controls="ksp-menu" aria-label="Meer verzendopties"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4 10l4-4 4 4"/></svg></button>
<div class="ksp__menu" id="ksp-menu" role="menu" aria-label="Verzendopties" hidden>
<button class="ksp__it" type="button" role="menuitem" tabindex="-1" data-msg="verstuurd met een kopie naar jou">Versturen met kopie naar mij</button>
<button class="ksp__it" type="button" role="menuitem" tabindex="-1" data-msg="ingepland voor morgen 9:00">Inplannen voor morgen 9:00</button>
<button class="ksp__it" type="button" role="menuitem" tabindex="-1" data-msg="opgeslagen als concept">Opslaan als concept</button>
</div>
</div>
<p class="ksp__st" role="status">Badkamer Delft, € 12.480</p>
</div>
</div>
</div>/* Gesplitste knop met menu · NedDev · eigen werk. */
.ksp{position:absolute;inset:0;display:flex;align-items:flex-end;justify-content:center;padding:12px 12px 14px;background:#f4f3f1;font-family:'Switzer',sans-serif;color:#0a0a0a}
.ksp *,.ksp *::before,.ksp *::after{box-sizing:border-box}
.ksp__box{display:flex;flex-direction:column;align-items:center;gap:6px;width:min(320px,100%)}
.ksp__split{position:relative;display:flex}
.ksp__main,.ksp__more{appearance:none;min-height:46px;margin:0;border:0;background:#0a0a0a;color:#fff;cursor:pointer;transition:background-color .16s ease}
.ksp__main{padding:0 18px;border-radius:4px 0 0 4px;font:600 15px/1 'Switzer',sans-serif}
.ksp__more{width:44px;display:grid;place-items:center;padding:0;border-left:1px solid #4a4743;border-radius:0 4px 4px 0}
.ksp__more svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;transition:transform .2s ease}
.ksp__more[aria-expanded="true"] svg{transform:rotate(180deg)}
.ksp__main:hover,.ksp__more:hover,.ksp__more[aria-expanded="true"]{background:#2b2926}
.ksp__main:focus-visible,.ksp__more:focus-visible{outline:2px solid #F5480F;outline-offset:2px;position:relative;z-index:1}
.ksp__menu{position:absolute;right:0;bottom:calc(100% + 6px);display:flex;flex-direction:column;width:250px;padding:4px;background:#fff;border:1px solid #d9d5ce;border-radius:8px;box-shadow:0 10px 24px rgba(10,10,10,.12);transform-origin:90% 100%;animation:ksp-in .16s cubic-bezier(.3,.7,.3,1)}
.ksp__menu[hidden]{display:none}
@keyframes ksp-in{from{opacity:0;transform:translateY(4px) scale(.97)}to{opacity:1;transform:none}}
.ksp__it{appearance:none;display:block;width:100%;min-height:32px;margin:0;padding:0 10px;border:0;border-radius:4px;background:transparent;color:#0a0a0a;text-align:left;font:500 14px/1 'Switzer',sans-serif;cursor:pointer}
.ksp__it:hover,.ksp__it:focus{background:#f4f3f1;outline:none}
.ksp__it:focus-visible{box-shadow:inset 3px 0 0 #F5480F}
.ksp__st{min-height:18px;margin:4px 0 0;font:400 13px/1.35 'Switzer',sans-serif;color:#5d5953;text-align:center}
.ksp__st.is-done{color:#0a0a0a;font-weight:500}
@media (prefers-reduced-motion:reduce){.ksp__menu{animation:none}.ksp__more svg{transition:none}}// Gesplitste knop met menu · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.ksp');if(!w)return;
var main=w.querySelector('.ksp__main'),more=w.querySelector('.ksp__more'),menu=w.querySelector('.ksp__menu'),st=w.querySelector('.ksp__st');
var its=[].slice.call(w.querySelectorAll('.ksp__it'));
function open(i){menu.hidden=false;more.setAttribute('aria-expanded','true');its[i||0].focus();}
function close(f){if(menu.hidden)return;menu.hidden=true;more.setAttribute('aria-expanded','false');if(f)more.focus();}
main.addEventListener('click',function(){st.classList.add('is-done');st.textContent='Offerte 2026-114 verstuurd naar j.dekker@voorbeeld.nl.';});
more.addEventListener('click',function(){menu.hidden?open(0):close(true);});
more.addEventListener('keydown',function(e){if(e.key==='ArrowUp'||e.key==='ArrowDown'){e.preventDefault();open(e.key==='ArrowUp'?its.length-1:0);}});
its.forEach(function(it,i){
it.addEventListener('click',function(){close(true);st.classList.add('is-done');st.textContent='Offerte 2026-114 '+it.getAttribute('data-msg')+'.';});
it.addEventListener('keydown',function(e){var n=its.length,k=e.key,to=null;
if(k==='ArrowDown')to=(i+1)%n;else if(k==='ArrowUp')to=(i-1+n)%n;else if(k==='Home')to=0;else if(k==='End')to=n-1;
else if(k==='Escape'){e.preventDefault();close(true);return;}else if(k==='Tab'){close(false);return;}
if(to!==null){e.preventDefault();its[to].focus();}});
});
document.addEventListener('pointerdown',function(e){if(!menu.hidden&&!menu.contains(e.target)&&!more.contains(e.target))close(false);});
}
init(document.querySelector('.jouw-container'));
More buttons
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →