Changing the color of an open Bootstrap 4 accordion panel when the page loads

I am looking to emphasize the panel that the user has opened. If a user clicks the button in the card header, the background turns red, which is working smoothly as demonstrated in the code snippet.

In certain scenarios, the first panel is open by default on page load, indicated by the class show. My objective is to have the background of this card header turn red on page load as well.

The buttons in the card headers are controlled using JavaScript, as shown in the code snippet.

I believe I need to use JavaScript to toggle classes.

Initially, I created a new class called highlight and included the following CSS:

.accordion .card-header.highlight {
    color: #fff;
    background-color: red;
}

Subsequently, I added the following JavaScript code (please note that I find JavaScript challenging to grasp, but I am slowly learning) in an attempt to set the background of the header of the open panel on page load.

$(document).ready(function(){
    // Add class highlight to panel with show class
    $(".collapse.show").each(function(){
        $(this).prev(".card-header").addClass("highlight");
    });
    
    // toggle highlight class
    $(".card-header .btn").click(function(){
        $(".card-header").toggleClass("highlight");
    });
});

It may seem messy, and it doesn't yield the desired outcome.

How can I set the background (red) of the header of the open panel on page load and how can I toggle classes using JavaScript?

Answer №1

You could simplify your code even further. Since you are already dynamically adding the wrapper on your accordion components, all you need to do is set the aria-expanded attribute to true for the ones with the show property. To achieve this, you can check for the presence of the show class and dynamically add the value as shown below:


function addIds(index) {
  $(this).attr("id", "accordion_" + parseInt(index + 1));
}

function addDataAttrs(index, value) {
  const num = index + 1;
  const isShowing = $(value).children(".show").length ? "true" : "false";

  $(value)
    .children(".card-header")
    .attr("id", "heading_acc_" + num);
  $(value)
    .find(".card-header > .card-title")
    .wrapInner(
      `<button class="btn btn-link" type="button" data-toggle="collapse" aria-expanded="${isShowing}"></button>`
    );
  $(value)
    .find(".card-header > .card-title > button")
    .attr({
      "data-target": "#collapse_acc_" + num,
      "aria-controls": "collapse_acc_" + num
    });
  $(value)
    .children(".collapse")
    .attr({
      id: "collapse_acc_" + num,
      "aria-labelledby": "heading_acc_" + num
    });
}

By following this approach, you can eliminate the need for extra code to add the highlight class, which also means you can do away with the related CSS rules.

Below is a functional example:

const $accordions = $(".accordion");
const $cards = $(".accordion > .card");

$.each($accordions, addIds);
$.each($cards, addDataAttrs);

function addIds(index) {
  $(this).attr("id", "accordion_" + parseInt(index + 1));
}

function addDataAttrs(index, value) {
  const num = index + 1;
  const isShowing = $(value).children(".show").length ? "true" : "false";

  $(value)
    .children(".card-header")
    .attr("id", "heading_acc_" + num);
  $(value)
    .find(".card-header > .card-title")
    .wrapInner(
      `<button class="btn btn-link" type="button" data-toggle="collapse" aria-expanded="${isShowing}"></button>`
    );
  $(value)
    .find(".card-header > .card-title > button")
    .attr({
      "data-target": "#collapse_acc_" + num,
      "aria-controls": "collapse_acc_" + num
    });
  $(value)
    .children(".collapse")
    .attr({
      id: "collapse_acc_" + num,
      "aria-labelledby": "heading_acc_" + num
    });
}
/* ========= Accordions ==========*/
.accordion .card .card-header {
  border-bottom: 1px solid grey
}

/* Accordion Standard */
.accordion:first-child {
  margin-top: 5px;
  border-radius: 0
}

.accordion h1,
.accordion h2,
.accordion h3,
.accordion h4,
.accordion h5,
.accordion h6 {
  font-size: 1.125rem
}

/* Rest of the CSS code remains unchanged for styling the accordions */

Answer №2

To apply the styles, you should choose the button that is targeted and then filter the n .card element that is currently open. In this case, use .card:first-of-type.

For instance:

/** Accordions JavaScript **/
/** Assign ids dynamically **/
$.each($(".accordion"), (function (index) {
   $(this).attr("id", "accordion_" + parseInt(index + 1));
}));

/** Assign interactions dynamically **/
$.each($(".accordion > .card"), (function (index, value) {
   var num = index + 1;
   $(value).children(".card-header").attr("id", "heading_acc_" + num);
   $(value).find(".card-header > .card-title").wrapInner("<button  class=\"btn btn-link\" type=\"button\" data-toggle=\"collapse\" aria-expanded=\"false\"></button>");
   $(value).find(".card-header > .card-title > button").attr({
      "data-target": "#collapse_acc_" + num,
      "aria-controls": "collapse_acc_" + num
   });
   $(value).children(".collapse").attr({
      id: "collapse_acc_" + num,
      "aria-labelledby": "heading_acc_" + num
   });
}));


$(document).ready(function(){
// Add class highlight to panel with show class
$(".collapse.show").each(function(){
    $(this).prev(".card-header").addClass("highlight");
});

// toggle highlight class
$(".card:first-of-type .card-header .btn").click(function(){
    $(".card-header").toggleClass("highlight");
});
});
/* ========= Accordions ==========*/
.accordion .card .card-header {
  border-bottom: 1px solid grey
}

/* Accordion Standard */
.accordion:first-child {
  margin-top: 5px;
  border-radius: 0
}

.accordion h1,
.accordion h2,
.accordion h3,
.accordion h4,
.accordion h5,
.accordion h6 {
  font-size: 1.125rem
}

.accordion .card {
  border: 0;
  border-radius: 0;
  padding-top: 0;
  padding-bottom: 0
}

.accordion .card .card-title {
  margin-bottom: 0;
  margin-top: 0;
  padding-top: 0;
  padding-bottom: 0
}

.accordion .card .card-title button {
  color: black
  font-weight: bold;
  font-size: 1.25rem;
  padding: 1.25rem;
  border: 1px solid grey
  border-radius: 0;
  background-color: #FFF;
  padding-left: 70px
}

.accordion .card .card-title button:hover,
.accordion .card .card-title button:focus {
  color: #174EA6
}

.accordion .card .card-title button::after {
  -webkit-font-smoothing: antialiased;
  display: inline-block;
  font-style: normal;
  font-variant: normal;
  text-rendering: auto;
  line-height: 1;
  font-family: "Font Awesome 6 Free";
  font-weight: 900;
  position: absolute;
  top: 1.5rem;
  left: 2rem
}

/* Open and Close Icon */
.accordion .card .card-title button[aria-expanded="true"]:after {
  content: "\f077";
  transform: rotate(0deg);
  transition: .3s all;
  color: black
}

.accordion .card .card-title button[aria-expanded="false"]:after {
  content: "\f054";
  transform: rotate(90deg);
  transition: .3s all;
  color: black
}

.accordion .card .card-header {
  padding: 0
}

.accordion .card .card-header button {
  border: 1px solid grey
  background-color: #fff;
  width: 100%;
  text-align: left
}

.accordion .card-body {
  border: 1px solid grey;
  background-color: white
}

/* Active Accordion Panel - Background and Text Color */
.accordion .card .card-header button[aria-expanded="true"] {
  background-color: red;
  color: #ffffff
}

.accordion .card:first-of-type .card-header.highlight  button {
    color: #fff;
    background-color: red;
}
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/js/bootstrap.min.js"></script>
     <link href=" https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.6.2/css/bootstrap.min.css" rel="stylesheet" />
    
    <h2>Accordion: Group of 2 - First panel open</h2>

       
            <!-- Accordion headings should be changed to respect page hierarchy -->
            <!--start accordion-->
            <div class="accordion mdb-shadow-4 my-5">
               <div class="card">
                  <div class="card-header ">
                     <h2 class="card-title">
                        Accordion 1 of 2
                     </h2>
                  </div>
                  <div class="collapse show">
                     <div class="card-body">
                        <p>Loren ipsum
                        </p>
                     </div>
                  </div>
               </div>
               <div class="card">
                  <div class="card-header">
                     <h2 class="card-title">
                        Accordion 2 of 2
                     </h2>
                  </div>
                  <div class="collapse">
                     <div class="card-body">
                        <p>Insert Accordion 2 of 2 content here.</p>
                     </div>
                  </div>
               </div>
            </div>
            <!--end accordion-->

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to create a two-toned horizontal rule tag?

Looking for a way to create a stylish two-toned divider line at the bottom of my header. It should be two pixels tall, with a grey top half and white bottom half. While I considered using two one pixel divs stacked together, I'm hoping there's a ...

Having trouble with installing Recharts through npm

When I try to install recharts using npm, I encounter the following error message in my console: npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! ...

Customizing font sizes for individual fonts within the same font family

I am designing a website in a language other than English. This means that the text on the webpage will be a mixture of English and other languages. In order to make sure the text displays correctly, I have set the font-family like this: p{ font-family: ...

Determine the vertical dimension of the containing element

<div class='contain'> <a href="#"> <div id="s1" class="sub" onclick="hello('1')">dasdad</div> </a> </div> <div class='contain'> <a href="#"> < ...

What is the process of matching a server response with the appropriate pending AJAX query?

Imagine a scenario where my web app utilizes AJAX to send out query #1, and then quickly follows up with query #2 before receiving a response from the server. At this point, there are two active event handlers eagerly waiting for replies. Now, let's ...

Vue.js is experiencing issues with updating attributes within nested v-for loops

Exploring the realm of vue.js and react, I am currently in the process of adapting a basic editable HTML table example found in a React book to further my understanding of Vue. Here is a breakdown of what occurs within the code: User clicks on a td elem ...

Using Variables and jQuery: Capturing Values and Putting Them to Use (Part Three)

Hey everyone, I recently posted a question about variables and jquery: how to capture value and use them (part 3). You can also find related questions about variables and jquery: part 1 and part 2. In my project, I needed to: 1. Capture a value from an ul ...

Finding the Perfect Placement for an Element in Relation to its Companion

Is there a way to achieve an effect similar to Position Relative in CSS using jQuery? I have developed a tooltip that I want to attach to various objects like textboxes, checkboxes, and other text elements. My code looks something like this: <input i ...

Changing text array to field identifiers with JavaScript

Is there an elegant way in ECMAScript 6 to transform a string array generated from a map function into field names within a dynamically created object? For instance, if I receive the following output from my map function: ["checkbox1Value", "checkbox4Val ...

You cannot define headers once they have been sent to the client. If you encounter a NextJS redirect issue, consider using res

I encountered an error when redirecting to a link from NextJS -> _app.js -> getInitialProps. I am trying to cache the last user language in cookies and redirect to it when the page is reloaded. It's working and the user is redirected, but I&apos ...

Limit the number of elements in an Angular object by using the filter function

I've implemented an angularjs filter method on a repeated array of items in an attempt to filter numbers using a limitTo filter. However, the result is not reflecting in the DOM. Below is the html code snippet: <div ng-controller="demo as d"> ...

Making an Ajax request from within an iframe using the easyXDM framework

I am currently utilizing easyXDM for enhancing the communication between a website and a shopping cart embedded within an iframe on my domain. Whenever a user adds an item to the shopping cart, I utilize easyXDM.Rpc to transmit the item details to the ifra ...

Issues with AJAX functionality in Django causing server to return 500 error

I am encountering a problem while attempting to make an AJAX request from my template. The request is supposed to take me to a URL and execute the view function. Unfortunately, I keep getting a 500 Error in my console. The error message in my Django log re ...

Using the jQuery.grep() method to sort through data

I have been attempting to filter data that is stored in a .js file using the jQuery.grep() method, but unfortunately, the data is not loading as expected. Data var myData = { "type": "FeatureCollection", "crs": { "type": "name", "properties": {"name": ur ...

Using AngularJS API within a standalone function: Tips and tricks

I'm diving into the world of AngularJS and I want to make an HTTP GET request to a distant server without messing up my current view code. After some research, I discovered a way to execute a function right after the HTML is loaded by using a standalo ...

Identifying the FireOS version using JavaScript

Can JavaScript be used to determine the version of FireOS that a Kindle device is running when accessing your website? ...

Ajax is unable to reach a file located in the directory UP from the application's main folder

Here is the ajax call I am using: <script> jQuery(document).ready(function(){ jQuery('#compare_btn').click(function(event){ event.preventDefault(); var id=jQuery('#compare_btn').attr('name'); alert(id); ...

The camera steadily advances in WebVR Cardboard using three.js technology, never stopping its forward movement

I've been experimenting with trying to create a smooth, continuous forward movement for the camera in a three.js/WebVR project, specifically with only a cardboard viewer needed. After much trial and error, I've discovered that the usual camera m ...

Managing the URLs of single page applications

Typically in a Single Page App (SPA), there is usually one main page that contains a side navigation menu with various anchor tags. These anchor tag URLs are managed by the angular/react/sammy js router, and the content of the main section is updated based ...

Create Joi Schema based on TypeScript types/interfaces

Searching for a way to convert Typescript types or interfaces into joi schema objects led me to various solutions that did the opposite, such as generating Typescript types/interfaces from joi schemas. I came across options like ts-interface-builder and ts ...