Ensure a button is automatically highlighted within an active class script

I have created a set of buttons that allow users to change the font family of the text. I would like the border and text color to update automatically when a specific option is selected.

Currently, the JavaScript code works well, but when the page first loads, the default font family (Georgia) is not highlighted until the user clicks on a button. How can I ensure that the default font style is already highlighted before any changes are made?

var fontbtns = document.getElementsByClassName("grid-item");
for (var i = 0; i < fontbtns.length; i++) {
  fontbtns[i].addEventListener("click", function() {
    var current = document.getElementsByClassName("fontactive");
    if (current.length > 0) {
      current[0].className = current[0].className.replace(" fontactive", "");
    }
    this.className += " fontactive";
  });
}
.grid-item.fontactive {
  border-color: #06a0ff;
  color: #06a0ff;
}
<div class="fontsgrid" id="fontlist">
  <button class="grid-item" id="ff-garamond" onclick="changeFontFamily('EB Garamond')">Garamond</button>
  <button class="grid-item" id="ff-palatino" onclick="changeFontFamily('Palatino')">Palatino</button>
  <button class="grid-item" id="ff-bookerly" onclick="changeFontFamily('Bookerly')">Bookerly</button>
  <button class="grid-item" id="ff-georgia" onclick="changeFontFamily('Georgia')">Georgia</button>
  <button class="grid-item" id="ff-baskerville" onclick="changeFontFamily('Baskerville')">Baskerville</button>
  <button class="grid-item" id="ff-montserrat" onclick="changeFontFamily('Montserrat')">Montserrat</button>
  <button class="grid-item" id="ff-futura" onclick="changeFontFamily('Futura')">Futura</button>
  <button class="grid-item" id="ff-opendyslexic3" onclick="changeFontFamily('OpenDyslexic3')">Open Dyslexic</button>
</div>

Answer №1

To incorporate the fontactive class into a specific button, simply add it to the desired button's class list.

var fontbtns = document.getElementsByClassName("grid-item");
for (var i = 0; i < fontbtns.length; i++) {
  fontbtns[i].addEventListener("click", function() {
    var current = document.getElementsByClassName("fontactive");
    if (current.length > 0) {
      current[0].className = current[0].className.replace(" fontactive", "");
    }
    this.className += " fontactive";
  });
}
.grid-item.fontactive {
  border-color: #06a0ff;
  color: #06a0ff;
}
<div class="fontsgrid" id="fontlist">
  <button class="grid-item" id="ff-garamond" onclick="changeFontFamily('EB Garamond')">Garamond</button>
  <button class="grid-item" id="ff-palatino" onclick="changeFontFamily('Palatino')">Palatino</button>
  <button class="grid-item" id="ff-bookerly" onclick="changeFontFamily('Bookerly')">Bookerly</button>
  <button class="grid-item fontactive" id="ff-georgia" onclick="changeFontFamily('Georgia')">Georgia</button>
  <button class="grid-item" id="ff-baskerville" onclick="changeFontFamily('Baskerville')">Baskerville</button>
  <button class="grid-item" id="ff-montserrat" onclick="changeFontFamily('Montserrat')">Montserrat</button>
  <button class="grid-item" id="ff-futura" onclick="changeFontFamily('Futura')">Futura</button>
  <button class="grid-item" id="ff-opendyslexic3" onclick="changeFontFamily('OpenDyslexic3')">Open Dyslexic</button>
</div>

It is recommended not to use the getElementsByClassName() method due to its impact on performance. Instead, opt for the querySelectorAll() method which returns a static node list.

Hence, with the adjustment, the code would look like:

// Utilize .querySelectorAll() as it simplifies looping
document.querySelectorAll(".grid-item").forEach(function(item){
  item.addEventListener("click", function() {
    document.querySelectorAll(".fontactive").forEach(function(element){
      element.classList.remove("fontactive");
    });
    item.classList.add("fontactive");
  });
});


function changeFontFamily(){}
.grid-item.fontactive {
  border-color: #06a0ff;
  color: #06a0ff;
}
<div class="fontsgrid" id="fontlist">
  <button class="grid-item" id="ff-garamond" onclick="changeFontFamily('EB Garamond')">Garamond</button>
  <button class="grid-item" id="ff-palatino" onclick="changeFontFamily('Palatino')">Palatino</button>
  <button class="grid-item" id="ff-bookerly" onclick="changeFontFamily('Bookerly')">Bookerly</button>
  <button class="grid-item fontactive" id="ff-georgia" onclick="changeFontFamily('Georgia')">Georgia</button>
  <button class="grid-item" id="ff-baskerville" onclick="changeFontFamily('Baskerville')">Baskerville</button>
  <button class="grid-item" id="ff-montserrat" onclick="changeFontFamily('Montserrat')">Montserrat</button>
  <button class="grid-item" id="ff-futura" onclick="changeFontFamily('Futura')">Futura</button>
  <button class="grid-item" id="ff-opendyslexic3" onclick="changeFontFamily('OpenDyslexic3')">Open Dyslexic</button>
</div>

An alternate approach involves using radio buttons to ensure only one selection at a time without necessitating loops in your code. By hiding and styling radio button labels as buttons, you achieve the desired functionality with minimal JavaScript involvement.

This technique introduces more HTML complexity but reduces reliance on JavaScript.

Refer to the inline comments below for details.

// Assign default font
document.body.style.fontFamily = "Consolas";

// Handle click events at parent level to set page font based on selected radio button within 'wrapper'
document.getElementById("wrapper").addEventListener("click", function(event){
  // Update page font to match value of clicked radio button 
  document.body.style.fontFamily = event.target.value;
});
/* Hide radio buttons */
input[type='radio'] { display:none; }

/* Default label style resembling buttons */
input[type='radio'] + label {
  display:inline-block;
  box-shadow:1px 1px grey;
  background-color:#e0e0e0;
  padding:5px;
  border-radius:3px;
  font-family:Arial, Helvetica, sans-serif;
  cursor:pointer;
  width: 80px;
  font-size:.6em;
  text-align:center;
}

/* Styling for checked labels */
input[type='radio']:checked + label {
  box-shadow:-1px -1px grey;
  background-color:#f78d32;
}
<div id="wrapper">
  <input type="radio" id="rad1" name="rad" value="Comic Sans MS">
  <label for="rad1">Comic Sans</label>

  <!-- Pre-selected choice using checked attribute -->
  <input type="radio" id="rad2" name="rad" value="Consolas" checked>
  <label for="rad2">Consolas</label>

  <input type="radio" id="rad3" name="rad" value="Calibri">
  <label for="rad3">Calibri</label>

  <input type="radio" id="rad4" name="rad" value="Georgia">
  <label for="rad4">Georgia</label>

  <input type="radio" id="rad5" name="rad" value="Arial">
  <label for="rad5">Arial</label>

  <input type="radio" id="rad6" name="rad" value="Montserrat">
  <label for="rad6">Montserrat</label>

  <input type="radio" id="rad7" name="rad" value="Baskerville Old Face">
  <label for="rad7">Baskerville</label>

  <input type="radio" id="rad8" name="rad" value="Harrington">
  <label for="rad8">Harrington</label>
</div>

<h1>Page Heading</h1>
<p>paragraph</p>
<p>paragraph</p>
<p>paragraph</p>
<p>paragraph</p>
<p>paragraph</p>
<p>paragraph</p>

Answer №2

To simplify this, utilize data attributes and relocate the event handler attachment to the script. By referencing the values of the data element, you can clearly see the fallback for a sans-serif font that has been added.

The removal of unnecessary IDs results in cleaner HTML structure.

function handleFontChangeClick(event) {
  const currentActive = document.querySelectorAll('.fontactive');
  currentActive.forEach(function(el) {
    el.classList.toggle("fontactive", false);
  });
  this.classList.toggle("fontactive", true);
}
// Attach a click handler to the nodes - in this case buttons
const fontbtns = document.querySelectorAll(".grid-item");
fontbtns.forEach(btn => btn.addEventListener('click', handleFontChangeClick));

// Direct way to set the class
// fontbtns[fontbtns.length - 1].classList.toggle("fontactive", true);

// A more efficient way to trigger "click" change?
// fontbtns[fontbtns.length - 1].click();

// Set a specific font from the list
const defaultFontFamily = "Georgia";
const fh = [...fontbtns].filter((el) => {
  return el.dataset.fontfam == defaultFontFamily;
}).pop().click(); // Automatically set on first one via click

// Set the fonts for the buttons based on their specified values
for (const btn of fontbtns) {
  btn.style.fontFamily = btn.dataset.fontfam;
}
.grid-item.fontactive {
  border-color: #06a0ff;
  color: #06a0ff;
}
<div class="fontsgrid" id="fontlist">
  <button class="grid-item" data-fontfam="EB Garamond">Garamond</button>
  <button class="grid-item" data-fontfam="Palatino">Palatino</button>
  <button class="grid-item" data-fontfam="Bookerly">Bookerly</button>
  <button class="grid-item" data-fontfam="Georgia">Georgia</button>
  <button class="grid-item" data-fontfam="Baskerville">Baskerville</button>
  <button class="grid-item" data-fontfam="Montserrat,sans-serif">Montserrat</button>
  <button class="grid-item" data-fontfam="Futura">Futura</button>
  <button class="grid-item" data-fontfam="OpenDyslexic3">Open Dyslexic</button>
</div>

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

What is the method for fetching a WebElement with a specific CSS attribute using JavascriptExecutor?

Currently, I am faced with a situation in which I need to locate a WebElement based on its CSS property, specifically the background-color. I successfully crafted the JQuery script below to pinpoint the element using the firefox console: $('.search-b ...

What is the best way to shift my content to the next line once it reaches a specific width in my paragraph

When a string is pulled from a database and inserted into a paragraph, it breaks perfectly if the paragraph has spaces. However, if a word is longer than the line, it goes off the page. How can I make it wrap to the next line instead of overflowing off the ...

IE - Adjusting the Width of the Vertical Spry Menu Bar

As I delve into the world of web design using Dreamweaver, I find myself faced with some challenges as a beginner. One specific issue I'm encountering is related to a vertical Spry Menu Bar on my website that functions well in most browsers except for ...

Incorporate External Web Page Information by Clicking a Button

Apologies if this question has already been asked, but despite my efforts to explore the available resources, I have not found a solution to my issue. I currently have an input field where users can enter their website, keyword, or industry. When they cli ...

Restricting data list values in AngularJS

Currently, I am facing a performance issue while trying to display approximately 2000 values retrieved through an API call using DataList in AngularJS. The page becomes extremely slow due to the large number of items being rendered. Is there a way to optim ...

Error encountered with Jest: SyntaxError - React Navigation - Unexpected export token found in [node_modules eact-navigationsrc eact-navigation.js:1]

Error Encountered with Jest:- The main issue arises from react navigation. There is an error occurring in jest related to the react-navigation node_modules folder. Error at: node_modules\react-navigation\src\react-navigation.js:1 Error Det ...

Refresh database records

I am currently using grails and I am exploring ways to update my database table utility by selecting values from two drop down menus. These drop down menus are populated with values from the database based on user selections from another drop down menu. My ...

Protractor is having difficulty finding the specified element or value

Here is some HTML code snippet: <tab id="briefcase" ng-controller="BriefcaseController as vm" active="main.uiState.briefcaseOpen"> <tab-heading> <i class="glyphicon glyphicon-briefcase"></i><br> ...

Creating seamless shading effects using three.js with Blender integration

When I import a Blender scene into a three.js environment, the curved faces appear flat. Is there a method to ensure that these surfaces remain smooth as intended? Despite calculating vertex normals and activating the smoothShaded option, the issue persis ...

Determine if a cookie is set in Vue.js without requiring a page refresh

My current goal with VUE is to make the login url disappear from the navigation bar as soon as the user logs in. After successfully logging in, the token cookie is set in the browser. However, the issue arises when the login url remains visible in the nav ...

Grab a parameter from the URL and insert it into an element before smoothly scrolling down to that

On a button, I have a URL that looks like this: www.mywebsite.com/infopage?scrollTo=section-header&#tab3 After clicking the button, it takes me to the URL above and opens up the tab labeled tab3, just as expected. However, I would like it to direct m ...

Aligning an SVG within a container div

I am trying to display an SVG image inside a fixed-position div. Here is the HTML: <div class="main"> <svg class="svg" viewBox="0 0 180 100"> <rect height="100%" width="100%" fill="#003300"></rect> </svg> </div> ...

How can one go about constructing abstract models using Prisma ORM?

Among my various prisma models, there are common fields such as audit fields like created_at and updated_at. model User { id Int @id @default(autoincrement()) created_at DateTime @default(now()) updated_at DateTime @updatedAt email ...

Trouble with CSS transitions not functioning while altering React state

Each time a user clicks on an accordion, the content should smoothly show or hide with a transition effect. However, the transition only seems to work when opening a closed accordion, not when closing an already open one! To get a clearer idea of this iss ...

What could be the reason behind my Javascript code returning "object object"?

I am a beginner with jQuery. I attempted to calculate the sum of items from my django views using jQuery. Here's what I have so far: $(document).ready(function() { var sch = $('#sch-books'); var gov = $('#gov-books'); ...

Stop Bootstrap 4 from automatically wrapping columns to the next row

I'm experiencing an issue with a component using Bootstrap 4 where a column is expanding to another row due to the presence of a long text element with the "text-truncate" class. This results in Chrome vertically stacking the column below its intended ...

What is the process for transforming this information into JSON format with Javascript?

I have a server response with data that needs to be converted to JSON using JavaScript. country=Philippines\r\n countryid=840\r\n operator=Globe Telecom Philippines\r\n operatorid=246\r\n connection_status=100\ ...

Adding a badge to a div in Angular 6: What you need to know!

How can I add a badge to a specific div in Angular 6? I have dynamic div elements in my HTML. I want to increase the counter for a specific div only, rather than increasing it for all divs at once. For example, I have five divs with IDs div1, div2, div3, ...

Dynamically Loading External JavaScript Files Depending on User Input

Looking for guidance on how to dynamically load a single javascript file out of several options based on user input in an HTML code. Any suggestions on how to achieve this task? Thank you! ...

Encountering a React Runtime issue: The element type is invalid, expecting a string for built-in components or a class/function for composite components

Here is a glimpse of my code: import { React, useState, useEffect } from 'react'; import { GoogleMapReact } from 'google-map-react'; import styles from './Location.module.scss'; import pinstyles from './TheMap.module.scss ...