How to make the dotted lines dynamic while having other functionalities (expand- collapse button on click of set1 or set2) intact. Do not want dotted line to go underneath data. So that it starts and ends like a connector between data. Fiddle showing the same: https://jsfiddle.net/vcjzn5hs/1/
Would appreciate your suggestion.
I am able to make dynamic dotted lines and expand-collapse work independently but not together. For your reference: Sample of how dynamic dotted lines should be http://jsfiddle.net/bwpugnd3/11/. But this example does not work along with expand collapse button.
Code snippet:
.flex {
display: flex;
justify-content: space-between;
}
.lev1,
.lev2,
.lev3 {
position: relative;
margin-top: 5px;
margin-left: 15px;
}
.lev1::after,
.lev2::after,
.lev3::after {
content: '';
position: absolute;
width: 80%;
top: 100%;
left: 50%;
transform: translateX(-50%);
margin: 0 6px;
height: 2px;
color: lightgrey;
margin-bottom: 4px;
background-image: linear-gradient(to right, currentColor 2px, transparent 1px);
background-size: 4px 2px;
}
.DataRightAlign {
word-wrap: break-word;
white-space: break-spaces;
margin-right: 20px;
margin-left: 10px;
color: black;
}
<!--jquery and bootstrap-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<div class="itemDiv">
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev1"> Set1 </a>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item1data</span>
<span class="DataRightAlign"> Set1val here</span>
</p>
</div>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item2</span>
<span class="DataRightAlign">Set1</span>
</p>
</div>
</div>
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev3">Set2 </a>
<div class="collapse multi-collapse lev3 show">
<p class="flex">
<span>item3</span>
<span class="DataRightAlign">Set2val</span>
</p>
</div>
</div>
One approach, and frankly the easiest, is below with explanatory comments in the code; please note that I removed all CSS from your own demo because it made it slightly easier to create the demo, but – of course – there's nothing to stop you adding your own CSS back:
/* a simple CSS reset to ensure the browser uses the same sizing
algorithm for element sizes; including the width and padding
within the declared sizes, also removing default margins
and padding: */
body {
block-size: 100vh;
padding-block: 1rem;
padding-inline: 1.5rem;
}
.itemDiv {
/* setting the inline-size of the element; inline-size is the axis
on which inline-content (such as <span> elements) is laid out,
and is perpendicular to the block-axis. In English the inline-axis
is the horizontal axis running left-to-right. The clamp() function
sets the preferred size of the element to 90%, with a 30rem
minimum-size and 1100px maximum size: */
inline-size: clamp(30rem, 90%, 1100px);
/* centering the element on the inline-axis: */
margin-inline: auto;
}
.flex {
display: flex;
gap: 0.5rem;
/* spacing the elements out: */
justify-content: space-between;
}
/* using the second span (noted in the HTML) to contain the line leading: */
.flex > span:nth-child(2) {
background-image:
/* using a repeating-linear-gradient() as the background-image: */
repeating-linear-gradient(
/* 90degrees causes the gradient to run horizontally, from an
origin on the left side: */
90deg,
/* currentColor is the currently-assigned color of the element, this
runs from 0 to 2px: */
currentColor 0 2px,
/* and we switch to a transparent "color" which starts at 2px and
runs for 3px until a point at 5px: */
transparent 2px 5px
);
/* positioning the repeating-linear-gradient() at 0 on the inline axis,
and at 100% minus 5px on the block-axis; 5px is something of a magic
number to line the dots of the background image to the approximate
baseline of the text in the adjacent elements: */
background-position: 0 calc(100% - 5px);
/* preventing the background from repeating: */
background-repeat: no-repeat;
/* setting the size of the background-image to be 100% of the width/inline-axis,
and 2px on the vertical/block-axis: */
background-size: 100% 2px;
/* this causes the element to grow to fill all available space: */
flex-grow: 1;
}
.accordion-button {
/* if an element can be clicked, and is interactive, I tend to assign the
following property and property-value to indicate that interactivity: */
cursor: pointer;
}
<!--jquery and bootstrap-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<!--html -->
<div class="itemDiv">
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev1"> Set1 </a>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item1data</span>
<!-- I feel bad about it, but the easiest way is to add an element to hold
the leading: -->
<span></span>
<span class="DataRightAlign"> Set1val here</span>
</p>
</div>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item2</span>
<span></span>
<span class="DataRightAlign">Set1</span>
</p>
</div>
</div>
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev3">Set2 </a>
<div class="collapse multi-collapse lev3 show">
<p class="flex">
<span>item3</span>
<span></span>
<span class="DataRightAlign">Set2val</span>
</p>
</div>
</div>
</div>
An alternative is to use a CSS generated content to hold the leading (the dots that lie between the item-data and set-value), this has problems though; again, explanatory comments are in the code:
/* a simple CSS reset to ensure the browser uses the same sizing
algorithm for element sizes; including the width and padding
within the declared sizes, also removing default margins
and padding: */
body {
block-size: 100vh;
padding-block: 1rem;
padding-inline: 1.5rem;
}
.itemDiv {
/* setting the inline-size of the element; inline-size is the axis
on which inline-content (such as <span> elements) is laid out,
and is perpendicular to the block-axis. In English the inline-axis
is the horizontal axis running left-to-right. The clamp() function
sets the preferred size of the element to 90%, with a 30rem
minimum-size and 1100px maximum size: */
inline-size: clamp(30rem, 90%, 1100px);
/* centering the element on the inline-axis: */
margin-inline: auto;
}
.flex {
display: flex;
gap: 0.5rem;
/* spacing the elements out: */
justify-content: space-between;
}
.flex > span:first-child {
/* here we use display: contents, which emulates "unwrapping" of the content
from the matched element, and placing it directly into its parent-element;
this means that both the <span> content and the ::after pseudo-element can
take part in the flex layout, acting as siblings: */
display: contents;
}
/* using the second span (noted in the HTML) to contain the line leading: */
.flex > span:first-child::after {
background-image:
/* using a repeating-linear-gradient() as the background-image: */
repeating-linear-gradient(
/* 90degrees causes the gradient to run horizontally, from an
origin on the left side: */
90deg,
/* currentColor is the currently-assigned color of the element, this
runs from 0 to 2px: */
currentColor 0 2px,
/* and we switch to a transparent "color" which starts at 2px and
runs for 3px until a point at 5px: */
transparent 2px 5px
);
/* positioning the repeating-linear-gradient() at 0 on the inline axis,
and at 100% minus 5px on the block-axis; 5px is something of a magic
number to line the dots of the background image to the approximate
baseline of the text in the adjacent elements: */
background-position: 0 calc(100% - 5px);
/* preventing the background from repeating: */
background-repeat: no-repeat;
/* setting the size of the background-image to be 100% of the width/inline-axis,
and 2px on the vertical/block-axis: */
background-size: 100% 2px;
content: '';
/* this causes the element to grow to fill all available space: */
flex-grow: 1;
}
.accordion-button {
/* if an element can be clicked, and is interactive, I tend to assign the
following property and property-value to indicate that interactivity: */
cursor: pointer;
}
<!--jquery and bootstrap-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<!--html -->
<div class="itemDiv">
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev1"> Set1 </a>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item1data</span>
<span class="DataRightAlign"> Set1val here</span>
</p>
</div>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item2</span>
<span class="DataRightAlign">Set1</span>
</p>
</div>
</div>
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev3">Set2 </a>
<div class="collapse multi-collapse lev3 show">
<p class="flex">
<span>item3</span>
<span class="DataRightAlign">Set2val</span>
</p>
</div>
</div>
</div>
Unfortunately, the use of:
.flex > span:first-child {
display: contents;
}
means that we can no longer style the element with background-color
, or border
and so on; this is an unavoidable consequence of this approach.
Finally, though, and thought of rather later than I'd like, we have the option of nesting flex-layouts as follows:
/* a simple CSS reset to ensure the browser uses the same sizing
algorithm for element sizes; including the width and padding
within the declared sizes, also removing default margins
and padding: */
body {
block-size: 100vh;
padding-block: 1rem;
padding-inline: 1.5rem;
}
.itemDiv {
/* setting the inline-size of the element; inline-size is the axis
on which inline-content (such as <span> elements) is laid out,
and is perpendicular to the block-axis. In English the inline-axis
is the horizontal axis running left-to-right. The clamp() function
sets the preferred size of the element to 90%, with a 30rem
minimum-size and 1100px maximum size: */
inline-size: clamp(30rem, 90%, 1100px);
/* centering the element on the inline-axis: */
margin-inline: auto;
}
.flex {
display: flex;
gap: 0.5rem;
/* spacing the elements out: */
justify-content: space-between;
}
.flex > span:first-child {
/* we assign display: flex to the element, this causes it to lay its
own children out according to the flex layout properties: */
display: flex;
/* this causes the element to grow to fill all available space within
its parent: */
flex-grow: 1;
/* we inherit the gap property from the parent, so that the gaps here
are the same as the gaps between this element and its sibling(s): */
gap: inherit;
}
.flex > span:first-child::after {
/* again, using the background image to create the leading: */
background-image:
/* using a repeating-linear-gradient() as the background-image: */
repeating-linear-gradient(
/* 90degrees causes the gradient to run horizontally, from an
origin on the left side: */
90deg,
/* currentColor is the currently-assigned color of the element, this
runs from 0 to 2px: */
currentColor 0 2px,
/* and we switch to a transparent "color" which starts at 2px and
runs for 3px until a point at 5px: */
transparent 2px 5px
);
/* positioning the repeating-linear-gradient() at 0 on the inline axis,
and at 100% minus 5px on the block-axis; 5px is something of a magic
number to line the dots of the background image to the approximate
baseline of the text in the adjacent elements: */
background-position: 0 calc(100% - 5px);
/* preventing the background from repeating: */
background-repeat: no-repeat;
/* setting the size of the background-image to be 100% of the width/inline-axis,
and 2px on the vertical/block-axis: */
background-size: 100% 2px;
content: '';
/* as with the parent element, we use flex-grow to allow the pseudo-element
to grow to fill the available space: */
flex-grow: 1;
}
.accordion-button {
/* if an element can be clicked, and is interactive, I tend to assign the
following property and property-value to indicate that interactivity: */
cursor: pointer;
}
<!--jquery and bootstrap-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<!--html -->
<div class="itemDiv">
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev1"> Set1 </a>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item1data</span>
<span class="DataRightAlign"> Set1val here</span>
</p>
</div>
<div class="collapse multi-collapse lev1 show">
<p class="flex">
<span>item2</span>
<span class="DataRightAlign">Set1</span>
</p>
</div>
</div>
<div>
<a class="accordion-button " data-toggle="collapse" data-target=".lev3">Set2 </a>
<div class="collapse multi-collapse lev3 show">
<p class="flex">
<span>item3</span>
<span class="DataRightAlign">Set2val</span>
</p>
</div>
</div>
</div>
References: