3

How to truncate dynamic text(with variable width) inside a nav-link or nav-text in a bootstrap navbar?

P.S.: With explicit width, this code just works fine, ex.: <a class="nav-link disabled text-truncate" style="max-width: 150px;"> but the width is unknown.

The expected behavior, is truncate text on desktop and mobile viewports, no matter which viewport size.

Codepen

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Dropdown
          </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li>
              <hr class="dropdown-divider">
            </li>
            <li><a class="dropdown-item" href="#">Something else here</a></li>
          </ul>
        </li>
        <li class="nav-item">
          <a class="nav-link disabled text-truncate">long long long long long long long long long long long long long long long long long long long long long long long long long long long text</a>
        </li>
      </ul>
      <div class="d-flex" role="search">
        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
        <button class="btn btn-outline-success" type="submit">Search</button>
      </div>
    </div>
  </div>
</nav>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

I've tried @isherwood suggestions, but without success:

First:

.flex-parent,
.flex-parent-parent,
.flex-parent-parent-parent {
  display: flex;
  padding: 10px;
  border: solid;
  min-width: 100px;
}

.flex-parent {
  min-width: 0;
}

.long-and-truncated {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Dropdown
          </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li>
              <hr class="dropdown-divider">
            </li>
            <li><a class="dropdown-item" href="#">Something else here</a></li>
          </ul>
        </li>
        <li class="nav-item">
          <div class="flex-parent-parent-parent">
            <div class="flex-parent-parent">
              <div class="flex-parent">
                <div class="flex-child long-and-truncated">
                  1. This is a loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string that is OK to truncate please and thank you
                </div>
              </div>
            </div>
          </div>

        </li>
      </ul>
      <div class="d-flex" role="search">
        <button class="btn btn-outline-success">Search</button>
      </div>
    </div>
  </div>
</nav>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

Second:

.wrapper {
  display: flex;
  /*   width: 200px; */
  align-content: stretch;
  padding: 5px;
  min-width: 0;
  border: 1px solid
}

.wrapper .child2 {
  flex-grow: 1;
  overflow: hidden;
}

.flex {
  display: flex;
  min-width: 0;
}

.el {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.child1 {
  background: red;
}

.child2 {
  background: lightblue;
}

.child3 {
  background: green;
}

.wrapper>* {
  padding: 5px;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
  <span class="navbar-toggler-icon"></span>
</button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
        Dropdown
      </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li>
              <hr class="dropdown-divider">
            </li>
            <li><a class="dropdown-item" href="#">Something else here</a></li>
          </ul>
        </li>
        <li class="nav-item">

          <div class="wrapper">
            <div class="child1">child1</div>
            <div class="child2">
              <div class="flex">
                <div class="el">long long long long long long long long long long long long long long long long long long long long text</div>
                <div>a</div>
              </div>
            </div>
            <div class="child3">child3</div>
          </div>

        </li>
      </ul>
      <div class="d-flex" role="search">
        <button class="btn btn-outline-success">Search</button>
      </div>
    </div>
  </div>
</nav>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>

Both(apparently) need a explicit width to truncate text. My text come from API, and have no length restriction, that cause in a layout mess.

sistematico
  • 117
  • 13
  • Does this answer your question? [How to make flex-box work with a nested child that needs truncated text?](https://stackoverflow.com/questions/71769806/how-to-make-flex-box-work-with-a-nested-child-that-needs-truncated-text) – isherwood Apr 06 '23 at 13:38
  • Or this? [text-overflow ellipsis on flex child not working](https://stackoverflow.com/questions/45813304/text-overflow-ellipsis-on-flex-child-not-working) – isherwood Apr 06 '23 at 13:39
  • @isherwood i'm not sure, but on first look(maybe i'm wrong) these two links have a fixed width. – sistematico Apr 06 '23 at 14:05
  • 1
    The width on the body is for demonstration purposes. The situation is the same as yours. This isn't really a Bootstrap question. – isherwood Apr 06 '23 at 14:08
  • 2
    Please update your question. The conversation is with the entire community, not just me. Post code, not images. Update the snippet demo or add another one. – isherwood Apr 06 '23 at 15:07

3 Answers3

1

Adding grid to wrapper class will work

.wrapper{
  display: grid;
  align-content: stretch;
  padding: 5px;
  min-width: 0;
  border: 1px solid
}
Sweety SK
  • 351
  • 1
  • 10
0

Here's your solution,

Notes:

  • The commented css at the bottom was my first attempt to achieve the result and was more concise it achieved it, but as bootstrap uses flex-wrap on smaller devices rather than changing flex direction, the overflow-x:hidden prevented the dropdown to show, so commented css prevent dropdown navbar item from showing its content.

  • Then I modified the solution by coming with some tweaks for the css behavior by specifying some small widths for items that I know would overflow and adding some media query rules and the solution is working fine, check it.

  • Finally, I made the text that overflows scrollabe when hovering over it while hiding its scrollbars, so truncated text can be scrolled through and seen entirely rather than being totally inaccessible.

.container-fluid-custom{
  width: 100vw;
}

.navbar-nav-custom {
  flex: 1;
  width: 0;
}

.nav-item-custom::-webkit-scrollbar {
  display: none;
}
.nav-item-custom {
  flex: 1;
  width: 0;
}

.nav-item-custom:hover{
  margin-right: 1rem;
  overflow: auto;
  -ms-overflow-style: none;  /* IE and Edge */
  scrollbar-width: none; /*  Firefox */
}

.nav-item-custom:hover .text-truncate{
  overflow: visible !important;
}

@media (max-width: 992px) {

  .show {
    width: 100%;
  }
 
  .navbar-nav {
    width: 100%;
    overflow-x: hidden;
  }

  .nav-item-custom {
    width: 100%;
  }

}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid container-fluid-custom">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse navbar-collapse-custom" id="navbarSupportedContent">
      <ul class="navbar-nav navbar-nav-custom me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Dropdown
          </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li>
              <hr class="dropdown-divider">
            </li>
            <li><a class="dropdown-item" href="#">Something else here</a></li>
          </ul>
        </li>
        <li class="nav-item nav-item-custom">
          <a class="nav-link disabled text-truncate">long long long long long long long long long long long long long long long long long long long long long long long long long long long text</a>
        </li>
      </ul>
      <div class="d-flex" role="search">
        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
        <button class="btn btn-outline-success" type="submit">Search</button>
      </div>
    </div>
  </div>
</nav>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>

commented CSS of first trial, where dropdown item got hidden by overflow-x: hidden. This isn't the solution, but for reference, if you want to try it and maybe come out with another solution.

/* .navbar-collapse-custom{
  overflow-x: hidden;
}

.navbar-nav-custom{
   white-space: nowrap;
   overflow-x: hidden;
   text-overflow: ellipsis;
  
}

.nav-item-custom{
  overflow-x:hidden;
} */

An advice:

  • with your progression on front end development, you would see custom made libraries such as bootstrap hinders your freedom of implementation, that's why in some cases you should create your own UI components from scratch fully customized to your own purpose.
Abdelrahman
  • 525
  • 1
  • 4
  • 13
0

I don't get your actual problem to be honest, you keep changing the problem scope by adding more nested elements or more flex elements. Here is a fix for your First and Second examples.

.expect-long {
  min-width: 0;
}
.expect-long *:has(.long) {
  min-width: 0;
  display: flex;
}
.long {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.nav-item:has(.long) {
  display: flex;
  align-items: center;
}
.navbar-collapse [role="search"] {
  flex-shrink: 0;
}


.wrapper {
  display: flex;
}
.wrapper>* {
  padding: 5px 15px;
}
.child1 {
  background: red;
}
.child2 {
  background: lightblue;
}
.child3 {
  background: green;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" />

    <nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse expect-long" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <li class="nav-item">
          <a class="nav-link active" aria-current="page" href="#">Home</a>
        </li>
        <li class="nav-item">
          <a class="nav-link" href="#">Link</a>
        </li>
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Dropdown
          </a>
          <ul class="dropdown-menu">
            <li><a class="dropdown-item" href="#">Action</a></li>
            <li><a class="dropdown-item" href="#">Another action</a></li>
            <li><hr class="dropdown-divider"></li>
            <li><a class="dropdown-item" href="#">Something else here</a></li>
          </ul>
        </li>
        <li class="nav-item">
          <div class="wrapper">
            <div class="child1">child1</div>
            <div class="child2">
              <div>
                <div>
                    <div>
                        <div class="long">long long long long long long long long long long long long long long long long long long long long text</div>
                    </div>
                </div>
                <div>a</div>
              </div>
            </div>
            <div class="child3">child3</div>
          </div>
        </li>
      </ul>
      <div class="d-flex" role="search">
        <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
        <button class="btn btn-outline-success" type="submit" onclick="changeItem()">Change</button>
      </div>
    </div>
  </div>
</nav>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script>