{"id":605,"date":"2020-05-14T18:56:21","date_gmt":"2020-05-14T18:56:21","guid":{"rendered":"https:\/\/www.antpace.com\/blog\/?p=605"},"modified":"2025-08-25T17:24:22","modified_gmt":"2025-08-25T17:24:22","slug":"drop-down-with-css-arrow","status":"publish","type":"post","link":"https:\/\/www.antpace.com\/blog\/drop-down-with-css-arrow\/","title":{"rendered":"Drop down with CSS arrow"},"content":{"rendered":"<p>Here&#8217;s a quick one about how to create a drop-down UI element with an arrow via CSS. The aim is to create a menu that has\u00a0drop-down sub-menus. Each drop-down should have an arrow that points up towards the parent element.<\/p>\n<p>Here&#8217;s the HTML to structure the menu:<\/p>\n<pre>&lt;div class=\"menu\"&gt;\n  &lt;div class=\"menu-item\"&gt;\n    &lt;span&gt;Menu Item&lt;\/span&gt;\n    &lt;div class=\"drop-down-menu\"&gt;\n      &lt;p&gt;Sub-item&lt;\/p&gt;\n      &lt;p&gt;Sub-item&lt;\/p&gt;\n      &lt;p&gt;Sub-item&lt;\/p&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n\n  &lt;div class=\"menu-item\"&gt;\n    &lt;span&gt;Menu Item 2&lt;\/span&gt;\n  &lt;\/div&gt;\n\n  &lt;div class=\"menu-item\"&gt;\n    &lt;span&gt;Menu Item 3&lt;\/span&gt;\n    &lt;div class=\"drop-down-menu\"&gt;\n      &lt;p&gt;Sub-item&lt;\/p&gt;\n      &lt;p&gt;Sub-item&lt;\/p&gt;\n      &lt;p&gt;Sub-item&lt;\/p&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n\n&lt;\/div&gt;\n<\/pre>\n<p>I nest the sub-menu within the parent item, and use CSS to show it when a user mouses-over:<\/p>\n<pre>.menu-item:hover .drop-down-menu{\n  display: block;\n}\n<\/pre>\n<p>I line the menu-items in a row by setting display to &#8216;inline-block&#8217;. This is preferred over just &#8216;inline&#8217;, so that their height property is respected. This is important because I will create space between the parent item and sub-menu. If the two elements don&#8217;t actually overlap, then the hover state will be lost, closing the drop-down. See what I mean:<\/p>\n<figure id=\"attachment_695\" aria-describedby=\"caption-attachment-695\" style=\"width: 349px\" class=\"wp-caption alignnone\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-695\" src=\"https:\/\/www.antpace.com\/blog\/wp-content\/uploads\/2020\/05\/drop-down-menu.png\" alt=\"Drop down menu with CSS\" width=\"349\" height=\"215\" \/><figcaption id=\"caption-attachment-695\" class=\"wp-caption-text\">The sub-menu element overlaps with the parent item, so that the hover state is not lost.<\/figcaption><\/figure>\n<p>I also set the parent item position to relative, so that the drop-down will be absolutely positioned respective to it.<\/p>\n<pre>.menu-item{\n  cursor: pointer;\n  height: 50px;\n  display: inline-block;\n  position: relative;\n}\n<\/pre>\n<p>Since the menu items have a height larger than the actual content, I apply borders to a child span within them:<\/p>\n<pre>.menu-item:first-child span{\n  border:none;\n}\n.menu-item span{\n  border-left: 1px solid black;\n  padding: 0 10px;\n}\n<\/pre>\n<p>The sub-menu styling is straight-forward. I set it to display: none, set a width, add a border and padding, and position it absolutely. Its top value pushes it off of the parent item a bit. Setting a left value to zero ensures that it will be aligned with its parent. (If you don&#8217;t set a left value, multiple sub-menus will all stack under the very first parent item.)<\/p>\n<pre>.drop-down-menu{\n  display: none;\n  width: 100px;\n  position: absolute;\n  background: white;\n  border: 1px solid #301B46;\n  padding: 20px;\n  top: 40px;\n  left: 0px;\n}\n<\/pre>\n<p>The next step is building the arrow in the drop-down menu. The challenge is making the arrow&#8217;s border blend seamlessly with the container&#8217;s border. The illusion is achieved by overlapping the :before and :after pseudo-elements.<\/p>\n<p>The triangle shape that forms the arrow is achieved by giving\u00a0 a bottom border to an element with no height or width. This code pen animation does a phenomenal job of explaining the idea:\u00a0<a href=\"https:\/\/codepen.io\/chriscoyier\/pen\/lotjh\">https:\/\/codepen.io\/chriscoyier\/pen\/lotjh<\/a><\/p>\n<p>The drop-down&#8217;s :before element creates the white triangle that is the heart of the arrow itself. This also creates the gap in the sub-menu&#8217;s actual top border<\/p>\n<p>The :after element creates another triangle that is behind and slightly above the first one &#8211; creating the illusion of a border that connects just right with the menu&#8217;s.<\/p>\n<p>The illusion can be better revealed by manipulating the position and border-width of these pseudo-elements in the inspector.<\/p>\n<p>Here is the code I used for those pseudo elements:<\/p>\n<pre>.drop-down-menu:before {\n  content: \"\";\n  position: absolute;\n  border-color: rgba(194, 225, 245, 0);\n  border: solid transparent;\n  border-bottom-color: white;\n  border-width: 11px;\n  margin-left: -10px;\n  top: -21px;\n  right: 65px;\n  z-index: 1;\n}\n\n.drop-down-menu:after {\n    content: \"\";\n    position: absolute;\n    right: 66px;\n    top: -21px;\n    width: 0;\n    height: 0;\n    border: solid transparent;\n    border-width: 10px;\n    border-bottom-color: #2B1A41;\n    z-index: 0;\n}\n<\/pre>\n<p>You can view the whole thing in action here:\u00a0<a href=\"https:\/\/codepen.io\/pacea87\/pen\/OJywqrj\">https:\/\/codepen.io\/pacea87\/pen\/OJywqrj<\/a><\/p>\n<p>Code generated from <a href=\"http:\/\/www.cssarrowplease.com\/\">CSS Arrow Please<\/a> helped me a lot when I was first figuring out how to do this right.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here&#8217;s a quick one about how to create a drop-down UI element with an arrow via CSS. The aim is to create a menu that has\u00a0drop-down sub-menus. Each drop-down should have an arrow that points up towards the parent element. Here&#8217;s the HTML to structure the menu: &lt;div class=&#8221;menu&#8221;&gt; &lt;div class=&#8221;menu-item&#8221;&gt; &lt;span&gt;Menu Item&lt;\/span&gt; &lt;div class=&#8221;drop-down-menu&#8221;&gt; &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.antpace.com\/blog\/drop-down-with-css-arrow\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Drop down with CSS arrow&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":3171,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,5],"tags":[],"class_list":["post-605","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-design","category-web-development"],"_links":{"self":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts\/605","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/comments?post=605"}],"version-history":[{"count":2,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts\/605\/revisions"}],"predecessor-version":[{"id":3173,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts\/605\/revisions\/3173"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/media\/3171"}],"wp:attachment":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/media?parent=605"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/categories?post=605"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/tags?post=605"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}