<Dropdown />
Toggle contextual overlays for displaying lists of links and more with Dropdowns.Component
1import React, { useRef, useState, useEffect } from "react";23import "./Styles/_dropdown.scss";45const Dropdown = ({ children }) => {6 const [visible, setVisible] = useState(false);78 const ref = useRef();9 useOnClickOutside(ref, () => setVisible(false));101112 return (13 <div ref={ref} className={`dropdown ${visible ? 'is-active' : ''}`}>14 <div className="dropdown-btn">15 <button onClick={() => setVisible(!visible)} className="button">16 <span>Dropdown button</span>17 <span className="icon is-small">18 <i className="fas fa-angle-down" aria-hidden="true" />19 </span>20 </button>21 </div>22 <div className="dropdown-menu">23 <div className="dropdown-content">24 {children}25 </div>26 </div>27 </div>28 );29};30export default Dropdown;3132export { DropdownItem } from './Components/DropdownItem'33export { DropdownDivider } from './Components/DropdownDivider'34353637// Hooks For Adding Functionalities.38const useOnClickOutside = (ref, handler) => {39 useEffect(() => {40 const listener = (event) => {41 // Do nothing if clicking ref's element or descendent elements42 if (!ref.current || ref.current.contains(event.target)) {43 return;44 }45 handler(event);46 };47 document.addEventListener("mousedown", listener);48 document.addEventListener("touchstart", listener);49 return () => {50 document.removeEventListener("mousedown", listener);51 document.removeEventListener("touchstart", listener);52 };53 }, [ref, handler]);54};
Styles
1$properties: (2 position: "",3 width: 12rem,4 bgclr: white,5);67.dropdown {8 display: inline-flex;9 position: relative;10 vertical-align: top;1112 &.is-active,13 &.is-hoverable:hover {14 .dropdown-menu {15 opacity: 1;16 transform: translateY(0);17 pointer-events: auto;18 }19 }2021 @if map-get($properties, position) == "right" {22 .dropdown-menu {23 left: auto;24 right: 0;25 }26 } @else if map-get($properties, position) == "up" {27 .dropdown-menu {28 bottom: 100%;29 padding-bottom: 4px;30 padding-top: initial;31 top: auto;32 }33 }3435 &-menu {36 position: absolute;37 left: 0;38 min-width: map-get($properties, width);39 padding-top: 5px;40 top: 100%;41 z-index: 20;42 opacity: 0;43 pointer-events: none;44 transform: translateY(-10px);45 transition: opacity 100ms ease-in-out, transform 100ms ease-in-out;46 }4748 &-content {49 background-color: map-get($properties, bgclr);50 border-radius: 0.375em;51 box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;52 padding-bottom: 0.5rem;53 padding-top: 0.5rem;54 }5556 &-item {57 display: block;58 color: grey;59 font-size: 0.875rem;60 line-height: 1.5;61 padding: 0.375rem 1rem;62 position: relative;63 }6465 &-divider {66 background-color: #ededed;67 border: none;68 display: block;69 height: 1.5px;70 margin: 0.5rem 0;71 }72}7374a.dropdown-item,75button.dropdown-item {76 padding-right: 3rem;77 text-align: inherit;78 white-space: nowrap;79 width: 100%;80 text-decoration: none;8182 &:hover {83 background-color: hsl(0, 0%, 96%);84 color: hsl(0, 0%, 4%);85 }8687 &.is-active {88 background-color: #485fc7;89 color: #fff;90 }91}
Usage
1