Ensure that only the collapsed portion of the div is clickable, while making sure that the expanded section remains unclick

I have a nested div with 'additional information' inside.

When the div is clicked, it expands to show the 'additional information'.

To prevent closing when clicking on the text within the 'additional information', I used .stopPropagation(), but the collapse still occurs if the borders or other areas are clicked.

I came across a post on Stack Overflow that was similar to what I needed (link), but couldn't quite get it to work as required.

Here is a codepen example (link) of my objective.

$('#collapsDiv').on('show.bs.collapse', function( event ) {
event.stopPropagation();
    console.log('Only happen when outter div is opened');
})
$('#collapseDiv').on('hide.bs.collapse', function( event ) {
event.stopPropagation();
console.log('Only happen when outter div is collapsed');
})
$('#additionalDiv').on('click', function( event ) {
    event.stopPropagation();
})

$('#collapseDiv').click(function(e) {
     if (e.pageY > $(this).offset().top + $(this).height()) {
          // bottom was clicked
          console.log('bottom clicked!');
          e.stopPropagation();
     } else {
          // up of the div was clicked
          console.log('top clicked');
     }
});
#collapseDiv {
cursor:pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
<div id="collapseDiv" class="alert alert-warning" data-toggle="collapse" href="#additionalDiv" role="button" aria-expanded="false" aria-controls="additionalDiv">
This Div shows by default - I used an alert to make it more visually obvious. Only this part should remain clickable. The hidden stuff should not be clickable. A bonus would be having the lower portion not have a pointer!
<div id="additionalDiv" class="collapse">
<div class="other-stuff">
<h2>This stuff should not be clickable</h2>
<p>There may be paragraphs here a user might want to copy/paste!</p>
<p>In a perfect world - even the bottom / sides would not trigger the collapse. This would only be collapsed by clicking the original div area.</p>
</div>
</div>
</div>
</div>

Although it seems to be functioning, clicks at the bottom can still cause the collapse - how do I extend this behavior to avoid clicks on the sides too?

On a side note, there appears to be a very small row at the bottom that triggers the collapse when clicked.

Answer №1

The padding on the space creates a clickable area.

No javascript is necessary for this functionality. Simply include an additional div specifically for toggling.

#collapseDiv { 
  padding: 0;
}

.my-toggle {
  cursor: pointer;
  padding: 20px;
}

#additionalDiv {
  padding: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" />
<div class="container">
  <div id="collapseDiv" class="alert alert-warning">
    <div class="my-toggle" data-toggle="collapse" href="#additionalDiv" role="button" aria-expanded="false" aria-controls="additionalDiv">
      This Div is visible by default - I utilized an alert to enhance its visibility. Only this section should be clickable. The
      hidden content should not be clickable. Ideally, the lower portion should not display a pointer either!
    </div>
    
    <div id="additionalDiv" class="collapse">
      <div class="other-stuff">
        <h2>This content should not be clickable</h2>
        <p>There might be text here that users may want to copy/paste!</p>
        <p>In an ideal scenario, even the bottom and sides would not trigger the collapse action. It should only collapse when clicking on the original div area.</p>
      </div>
    </div>
  </div>
</div>

Answer №2

To improve the design, I suggest moving the additional div outside of the clickable one and adding padding to the sub-containers while applying styling to the main container.

The issue lies in the fact that the container's padding is extending the clickable area around the collapsible div.

.container--nopad {
    padding: 0;
}

#collapseDiv, #additionalDiv {
    padding: 20px;
}


<div class="container container--nopad alert alert-warning">
    <div id="collapseDiv" data-toggle="collapse" href="#additionalDiv" role="button" aria-expanded="false" aria-controls="additionalDiv">
        This Div is visible by default - using an alert for visual emphasis. Only this section should be clickable. The hidden content should not trigger a click. It would be ideal for the lower portion to not display as a pointer either!
    </div>
    <div id="additionalDiv" class="collapse">
        <div class="other-stuff">
            <h2>This content should not be clickable</h2>
            <p>There could be paragraphs here meant for copying/pasting!</p>
            <p>Ideally, even the bottom/sides wouldn't activate the collapse. Clicking the original div area should be the only way to trigger the collapse.</p>
        </div>
    </div>
</div>

CodePen link: https://codepen.io/dmgig/pen/EpzGLG

Answer №3

The issue lies with the padding in the container div. To fix this, remove the padding from the container div and add it to both inner elements instead.

$('#collapsDiv').on('show.bs.collapse', function( event ) {
event.stopPropagation();
console.log('Will only trigger when outer div is opened');
})
$('#collapseDiv').on('hide.bs.collapse', function( event ) {
event.stopPropagation();
console.log('Will only trigger when outer div is collapsed');
})
$('#additionalDiv').on('click', function( event ) {
event.stopPropagation();
})

$('#collapseDiv').click(function(e) {
if (e.pageY > $(this).offset().top + $(this).height()) {
// The bottom was clicked
console.log('The bottom was clicked!');
e.stopPropagation();
} else {
// The top part of the div was clicked
console.log('The top was clicked');
}
});
#collapseDiv {
cursor:pointer;
padding-left: 0;
padding-right: 0;
}
#collapseDiv .triggerDiv, 
#collapseDiv #additionalDiv {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/js/bootstrap.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
<div id="collapseDiv" class="alert alert-warning" data-toggle="collapse" href="#additionalDiv" role="button" aria-expanded="false" aria-controls="additionalDiv">
<div class="triggerDiv">This Div displays by default - I used an alert to make it more visually noticeable. Only this section should be clickable. The hidden content should not be clickable. Additionally, it would be ideal for the lower portion to have no pointer interaction!</div>
<div id="additionalDiv" class="collapse">
<div class="other-stuff">
<h2>This content should not trigger a collapse</h2>
<p>There could be paragraphs here that users might want to copy/paste!</p>
<p>Ideally, even clicking on the sides or bottom would not trigger the collapse. It should only collapse when clicking on the original div area.</p>
</div>
</div>
</div>
</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

Vue.js's two-way data binding feature is currently functioning in only one direction

Here is an example of my code: <input type="text" v-model="selectedPost.title" v-bind:value="selectedPost.title"> and this is my Vue.js application: var app = new Vue({ el: '#app', data: { selectedPost: {} } }); ...

The button's unclickability is due to the zIndex being set to -1

How can I create a clickable button? https://i.sstatic.net/BXOjz.png Feel free to check out the sandbox example here: https://codesandbox.io/s/m5w3y76mvy ...

Combination of AngularJS and jQuery

I have a page in which additional input fields are dynamically added based on the selection made in a drop-down menu. This page is powered by angularjs, but I had to use jQuery specifically for adding these extra input fields. Here is the HTML code snippe ...

Generating a collection of items within a JavaScript object

Struggling with sending a json object to a java API backend that requires an Object containing a list of objects. Wondering if it's possible to create a list of objects inside a javascript Object. While I know we can create an "Array" of objects with ...

Encountered a network error: A rogue token < was found in JSON at position 0 within a new Apollo

https://i.sstatic.net/D25ai.png const httpLink = createHttpLink({ uri: 'http://localhost:3090/' }) const client = new ApolloClient({ link: httpLink, cache: new InMemoryCache() }) client.query({ query: gql` query users { ...

Oops! An error has occurred: The requested method 'val' cannot be called on an undefined object

I am struggling with this issue. This is the code that I am currently working on: http://jsfiddle.net/arunpjohny/Jfdbz/ $(function () { var lastQuery = null, lastResult = null, // new! autocomplete, processLocation = function ...

tips for transitioning between various json entities

Recently, I created a login page code using JavaScript that runs on a Node Express.js server. Users can input their username/email and password, and all the data gets stored in a JSON file structured like this: {"username":"admin"," ...

Achieving full coverage of cell content within a cell area by utilizing align-items in CSS Grid

Is it possible to achieve two conflicting goals using CSS Grid? In my design, I want the content in each cell to be vertically centered using align-items: center; At the same time, I need the entire area of the cell to be filled with color. However, ...

Efficient ways to clear all input fields within a React div component

import "./App.css"; import { useState } from "react"; import { useSelector, useDispatch } from "react-redux"; import { addUser} from "./features/Users"; function App() { const dispatch = useDispatch(); const use ...

What is the method for creating a line break in text?

Here is some example code I have: <h3 class="ms-standardheader"> <nobr> Reasons for proposals selected and not selected </nobr> </h3> Now I also have an image to show. The problem is that my text appears too large, so I a ...

Tips for displaying animations only the first time using HTML and CSS:

Upon the initial visit to my website, a captivating animation introduces itself with the words "Hello. I'm Bob" as it gracefully fades into view. Navigating through the menu bar allows users to explore different sections of the site. However, there ...

Executing Jquery ajax calls in sequence to ensure response order

I am facing a challenge in my plugin where I need to make sequential ajax calls and handle the responses accordingly. The issue is that the responses do not match the order of the calls, and using async: false is not an option for me. var dynamicValues = ...

A step-by-step guide on generating a dynamic JSON file with JavaScript

I am in need of generating a JSON structure that follows this specific format: {"content": { "properties": { "area_id": "20", "origin": "3", "axis": "1", "x_start": "00", "x_end": "99", "y_start": "00", ...

How can I apply red border styling only after the first click in MUI React?

I am currently working with MUI Textfields and I have a specific styling requirement. I would like the field to display a red outline only after the first click, if the input is left blank or deleted. Essentially, I want the field to appear normal initiall ...

Looping to run an async process (sequilize.authenticate) multiple times until successful

I need my microservice to wait for the database to become available before proceeding. There is a sidecar Cloud SQL proxy involved that requires some time for the database connection. My current approach involves a for loop that retries connecting after a ...

A guide to implementing daily function calls for a week utilizing the @nestjs/scheduler module

Is there a way to schedule a function to run every day for a period of 7 days using Nestjs (@nestjs/scheduler)? @Cron(new Date(Date.now() + (24*60*60*1000) * 7) function() { console.log("This should get called each day during the next 7 days") ...

Optimal practices for naming divs in XHTML/CSS

Is it acceptable to use spaces in div names like this? <div class="frame header">Some content here</div> Having a space in the name might require separate CSS classes such as: .frame { display: block; } .header { background-color: #efefef; } ...

Generate a dynamic file import loop within a React application

Suppose I have a directory containing several .md files: /static/blog/ example_title.md another_example.md three_examples.md and an array that includes all the titles: const blogEntries = ["example_title", "another_example", "three_examples"] In ...

Blank page received upon submission of Laravel Select2 application

I'm experiencing an issue with submitting a form using select2. After submission, I receive a completely blank page. I'm not sure why the controller is not working properly. All I need is to send the store id. <form id='filter' act ...

What could be causing the images within these unordered list items not to appear in a straight line horizontally?

I am having trouble creating a carousel to display images in a horizontal row using an unordered list. The issue I'm facing is that the list items are not aligning inline as expected. The problem lies in the images within the unordered list not appear ...