Join
🚧 WORK IN PROGRESS: A CSS utility component that allows you to join two or more elements together. This looks best when the items have borders or background colors. 🚧
| Class name | Type | |
|---|---|---|
.prs-join |
Component | Container |
.prs-join-vertical |
Modifier | Stacked |
.prs-join-item |
Part | Child container |
-
Default
The markup is very lenient in cases where deep nesting is required.
<div class="prs-join"> <button class="prs-btn prs-btn-secondary prs-join-item">1</button> <div><button class="prs-btn prs-btn-secondary prs-join-item">2</button></div> <button class="prs-btn prs-btn-secondary prs-join-item">3</button> </div> -
Vertical
The markup is very lenient in cases where deep nesting is required.
<div class="prs-join prs-join-vertical"> <button class="prs-btn prs-btn-secondary prs-join-item">1</button> <span><button class="prs-btn prs-btn-secondary prs-join-item">2</button></span> <button class="prs-btn prs-btn-secondary prs-join-item">3</button> </div> -
Advanced
An example of a real-world use case.
<div class="prs-join w-full max-w-xs"> <div> <label><input class="prs-input prs-join-item" placeholder="Search" aria-label="Search query" /></label> </div> <label> <select class="prs-input prs-join-item w-auto max-w-[6.25rem]" aria-label="Filter option"> <option disabled selected>Filter</option> <option>Title</option> <option>Genre</option> <option>Option with a very long label...</option> </select> </label> <button class="prs-btn prs-btn-primary prs-btn-square prs-join-item" aria-label="Search"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" role="img"> <use href="/_assets/prs-icons.svg#nav-search" /> </svg> </button> </div>
CSS
Full Library
Component Only
.prs-join {
--join-ss: 0;
--join-se: 0;
--join-es: 0;
--join-ee: 0;
display: inline-flex;
align-items: stretch;
& :where(.prs-join-item) {
border-start-start-radius: var(--join-ss, 0);
border-start-end-radius: var(--join-se, 0);
border-end-end-radius: var(--join-ee, 0);
border-end-start-radius: var(--join-es, 0);
& * {
--join-ss: var(--prs-radius-btn);
--join-se: var(--prs-radius-btn);
--join-es: var(--prs-radius-btn);
--join-ee: var(--prs-radius-btn);
}
}
& > .prs-join-item:where(:first-child) {
--join-ss: var(--prs-radius-btn);
--join-se: 0;
--join-es: var(--prs-radius-btn);
--join-ee: 0;
}
& :first-child:not(:last-child) {
& :where(.prs-join-item) {
--join-ss: var(--prs-radius-btn);
--join-se: 0;
--join-es: var(--prs-radius-btn);
--join-ee: 0;
}
}
& > .prs-join-item:where(:last-child) {
--join-ss: 0;
--join-se: var(--prs-radius-btn);
--join-es: 0;
--join-ee: var(--prs-radius-btn);
}
& :last-child:not(:first-child) {
& :where(.prs-join-item) {
--join-ss: 0;
--join-se: var(--prs-radius-btn);
--join-es: 0;
--join-ee: var(--prs-radius-btn);
}
}
& > .prs-join-item:where(:only-child) {
--join-ss: var(--prs-radius-btn);
--join-se: var(--prs-radius-btn);
--join-es: var(--prs-radius-btn);
--join-ee: var(--prs-radius-btn);
}
& :only-child {
& :where(.prs-join-item) {
--join-ss: var(--prs-radius-btn);
--join-se: var(--prs-radius-btn);
--join-es: var(--prs-radius-btn);
--join-ee: var(--prs-radius-btn);
}
}
& > :where(:not(:first-child)) .prs-join-item {
margin-block-start: 0;
margin-inline-start: calc(var(--prs-border-btn, 1px) * -1);
}
}
.prs-join-item {
&:where(:not(:first-child)) {
margin-block-start: 0;
margin-inline-start: calc(var(--prs-border-btn, 1px) * -1);
}
&:where(:focus-visible) {
position: relative;
z-index: 1;
}
}
.prs-join-vertical {
flex-direction: column;
& > .prs-join-item:first-child {
--join-ss: var(--prs-radius-btn);
--join-se: var(--prs-radius-btn);
--join-es: 0;
--join-ee: 0;
}
& :first-child:not(:last-child) {
& .prs-join-item {
--join-ss: var(--prs-radius-btn);
--join-se: var(--prs-radius-btn);
--join-es: 0;
--join-ee: 0;
}
}
& > .prs-join-item:last-child {
--join-ss: 0;
--join-se: 0;
--join-es: var(--prs-radius-btn);
--join-ee: var(--prs-radius-btn);
}
& :last-child:not(:first-child) {
& .prs-join-item {
--join-ss: 0;
--join-se: 0;
--join-es: var(--prs-radius-btn);
--join-ee: var(--prs-radius-btn);
}
}
& > .prs-join-item:only-child {
--join-ss: var(--prs-radius-btn);
--join-se: var(--prs-radius-btn);
--join-es: var(--prs-radius-btn);
--join-ee: var(--prs-radius-btn);
}
& :only-child {
& .prs-join-item {
--join-ss: var(--prs-radius-btn);
--join-se: var(--prs-radius-btn);
--join-es: var(--prs-radius-btn);
--join-ee: var(--prs-radius-btn);
}
}
& > :where(:not(:first-child)) .prs-join-item {
margin-block-start: calc(var(--prs-border-btn, 1px) * -1);
margin-inline-start: 0;
}
& .prs-join-item {
&:where(:not(:first-child)) {
margin-block-start: calc(var(--prs-border-btn, 1px) * -1);
margin-inline-start: 0;
}
}
}
Coming soon...