// a simple function to create new elements, with Object.assign() to set their properties:
const create = (tag, props) => Object.assign(document.createElement(tag), props),
// an arrow function that takes two numbers:
// startNumber: the number that should normally be in the centrepoint of the range,
// and the size of the range itself, these both have default values (adjust as required):
generateRange = (startNumber = 5, range = 7) => {
// here we find the minimum value, by taking the supplied (or default) startNumber
// and subtracting the floored result of the range divided by 2:
let minValue = startNumber - Math.floor(range / 2);
// if that minimum value is less than 1:
if (minValue < 1) {
//we set the minimum value to 1:
minValue = 1;
}
// creating the Array of numbers:
let baseRange = Array.from({
// setting the length of the created Array:
length: 7
}).map(
// passing in the index of the current array-element,
// and adding the current index to the supplied minValue:
(_, i) => i + minValue);
// returning the created range:
return baseRange;
}
// iterating over the collection of <li> elements in the document,
// using NodeList.prototype.forEach():
document.querySelectorAll('li').forEach(
// passing the current <li> element, and the index of that
// element, to the function body:
(el, i) => {
// adding 1 to the zero-based index (this is - admittedly -
// entirely unnecessary, but I did it anyway):
let rangeStartValue = i + 1;
// appending a created <span> to the current <li>
el.append(create('span', {
// setting the textContent of that <span>:
textContent: rangeStartValue
}));
// creating a range of numbers, passing the rangeStartValue,
// and iterating over the resulting Array using Array.prototype.forEach():
generateRange(rangeStartValue).forEach(
// passing the current array-element (an integer):
(rangeValue) => {
// for each element we append a created <a> element:
el.append(
create('a', {
// with its textContent set to the current array-element value:
textContent: rangeValue,
// setting the href property of the element to a fragment identifier
// followed by the current array-element value:
href: `#${rangeValue}`,
// if the current rangeValue is exactly equal to the rangeStartValue,
// we add the class-name of 'current', otherwise we add an empty string
// (which results in the 'class' attribute being present, but containing
// no class-names:
className: rangeValue === rangeStartValue ? 'current' : 'other'
})
);
});
});
li {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
gap: 0.5rem;
margin-block: 0.25em;
}
span {
flex-basis: 100%;
}
span::before {
content: 'Starting at ';
}
span::after {
content: ': ';
}
a {
border: 1px solid currentColor;
color: rebeccapurple;
flex-basis: 3em;
flex-grow: 1;
padding: 0.5rem;
text-align: center;
}
.current {
background-color: skyblue;
color: white;
}
<ol>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ol>