skip to Main Content

I’m making a box containing multiple tags and an input field that allows to enter a new tag. This box should look and function alike the following tag form from YouTube:

YouTube Tags

This layout is a box that contains the list of already added tags, as well as an invisible input field that allows to add more tags to the list. This input field stretches to the leftover width of the parent block.

Here is the HTML code that I have:

<div class="box">
    <ul>
        <li>added tag 1</li>
        <li>added tag 2</li>
    </ul>

    <input type="text" placeholder="input new tag" />
</div>

I style already added tags as list items inside <ul> because, essentially, added tags are a list of items, and this seems the most natural markup for them.

My question is about styling: in that scenario, how do I make the input behave just like it does in YouTube’s example provided above? If I assign display: inline-flex to this <ul> and display: flex to the box div, then the input will get aligned in the next row instead of occupying the remaining place of the last partially filled row. Putting the input inside of the <ul> and setting the <ul>‘s display mode to flex would work, but it is invalid HTML because <ul> should only contain <li>‘s.

3

Answers


  1. You could add the input to the last item in the list:

    .box {
      background: #333;
    }
    
    .box ul,
    .box input {
      display: inline-block;
    }
    
    .box ul li {
      display: inline-block;
      background: #FFF;
      padding: 5px;
      border-radius: 20px;
      margin-top: 5px;
    }
    <div class="box">
      <ul>
        <li>stack overflow</li>
        <li>how to use stack overflow</li>
        <li>tutorial</li>
        <li>css overflow</li>
        <li>talent on stack overflow</li>
        <li>buffer overflow tutorial</li>
        <li>ask stack overflow</li>
        <li>stack overflow rude</li>
        <li>stack overflow jobs</li>
        <li>tech talent on stack overflow</li>
        <li>buffer overflow tutorial step by step</li>
        <li>recruit on stack overflow</li>
        <li>stack overflow visual studio code</li>
        <li>what is stack overflow</li>
        <li>stack overflow vs code</li>
        <li>stack overflow search</li>
        <li>css overflow tutorial in hindi</li>
        <li><input type="text" placeholder="input new tag" /></li>
      </ul>
    </div>
    Login or Signup to reply.
  2. As per your comment to Douwe de Haan’s post, you can indeed use display: contents to ignore the ul container. See the example below.

    Display: contents on css-tricks and MDN

    .box {
      width: 20rem;
      height: 12rem;
      border: 2px solid #0E68D3;
      border-radius: 0.25rem;
      padding: 0.5rem;
      display: flex;
      align-items: baseline;
      align-content: flex-start;
      flex-wrap: wrap;
    }
    
    .box ul {
      display: contents;  
    }
    
    .box ul li {
      list-style-type: none;
      margin: 0.25rem;
      padding: 0.5rem 1rem;
      background-color: #E9E9E9;
      border-radius: 100vh;
      white-space: nowrap;
    }
    
    .box input {
      flex-grow: 1;
    }
    <div class="box">
        <ul>
          <li>added tag 1</li>
          <li>added tag 2</li>
          <li>added tag three</li>
        </ul>
        <input type="text" placeholder="input new tag" />
    </div>
    Login or Signup to reply.
  3. Using display: contents

    With display: contents, we can replace <ul> with its children in regards to CSS layout. That way we can lay out the input and the list-items together.

    Note: At the time of writing, some browsers come with accessibility issues when using display: contents. If this was not the case, then I’d suggest using display: contents.

    Not using a list

    If we were to ignore the requirement of placing the tags in a list, then we could have them as siblings to the input. That flat structure allows for easier styling, e.g. with CSS Flexbox:

    .box {display: flex}
    .box input {flex-grow: 1}
    
    /*Allow resizing; observe the behaviour!*/
    .box {
      overflow: hidden;
      resize: both;
    }
    
    /*Ignore; presentational*/
    .box {border: 1px solid black}
    .box>ul {
      margin: 0;
      padding: 0;
      list-style-type: none; /*Remove list-markers*/
    }
    .box>ul>li {background-color: #ddd}
    <div class="box">
      <span>added tag 1</span>
      <span>added tag 2</span>
      <span>added tag 3</span>
      <span>added tag 4</span>
      <input placeholder="input new tag">
    </div>

    Using inline elements

    We want the tags and the input to flow like inline-level elements, therefore I suggest using display: inline (or similar):

    .box > ul {display: inline}
    .box > ul > li {display: inline-block}
    
    /*Allow resizing; observe the behaviour!*/
    .box {
      overflow: hidden;
      resize: both;
    }
    
    /*Ignore; presentational*/
    .box {border: 1px solid black}
    .box>ul {
      margin: 0;
      padding: 0;
      list-style-type: none; /*Remove list-markers*/
    }
    .box>ul>li {background-color: #ddd}
    <div class="box">
      <ul>
        <li>added tag 1</li>
        <li>added tag 2</li>
        <li>added tag 3</li>
        <li>added tag 4</li>
      </ul>
      <input placeholder="input new tag">
    </div>

    Note: You may want to prefer inline-block or similar for the tags to use a formatting context other than inline formatting, which doesn’t honour some vertical styling (e.g. margin, padding, border).


    The reason that display: inline-flex on <ul> won’t place the input in its last partially filled line is:

    The inline-flex value inlines <ul> as one (flex) container. Another element cannot be placed in that container’s flow.

    However, the inline value makes <ul> an inline-level element. It can be wrapped according to its surrounding flow into line boxes. Line boxes may partially fill a line, so following elements can be placed along the same line.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search