Skip to content

Instantly share code, notes, and snippets.

@Mulperi
Last active July 30, 2021 11:50
Show Gist options
  • Save Mulperi/8c457459266e03ad587d87ec9bd822d8 to your computer and use it in GitHub Desktop.
Save Mulperi/8c457459266e03ad587d87ec9bd822d8 to your computer and use it in GitHub Desktop.
React simple custom hook for dropdown menu
import React, { Component, useEffect, useRef, useState } from 'react';
import { render } from 'react-dom';
import './style.css';
interface AppProps {}
interface AppState {
name: string;
}
function useDropdown(props: any) {
const [visible, setVisible] = useState(false);
const dropdownContentRef = useRef();
useEffect(() => {
const clickCallback = e => {
const clickedOutside =
dropdownContentRef.current !== null &&
!dropdownContentRef.current.contains(e.target);
if (clickedOutside) {
setVisible(false);
}
};
if (visible) {
window.addEventListener('click', clickCallback);
}
return () => {
window.removeEventListener('click', clickCallback);
};
}, [visible]);
return (
<div
className="dropdown--container"
style={{
position: 'relative',
display: 'inline'
}}
>
<button onClick={() => setVisible(!visible)}>{props.text}</button>
{visible && (
<div
ref={dropdownContentRef}
className="dropdown--content"
id={props.contentId}
style={{
width: '200px',
boxShadow: '2px 2px 2px rgba(0,0,0,0.1)',
position: 'absolute',
background: 'white',
border: '1px solid grey',
right: props.alignRight ? 0 : 'auto'
}}
>
<ul style={{ listStyleType: 'none', margin: 0, padding: 0 }}>
{props.items.map((item, i) => (
<li key={i}>
{item.type === 'text' && <span>{item.text}</span>}
{item.type === 'link' && <a href={item.href}>{item.text}</a>}
</li>
))}
</ul>
</div>
)}
</div>
);
}
function Test() {
const menu = useDropdown({
text: 'Menu1',
items: [
{ type: 'text', text: 'Menu1: One' },
{ type: 'text', text: 'Menu1: Two' },
{ type: 'link', href: '/users', text: 'users' }
]
});
const menu2 = useDropdown({
text: 'Menu2',
alignRight: true,
items: [
{ type: 'text', text: 'Menu2: one' },
{ type: 'text', text: 'Menu2: two' }
]
});
return (
<section style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>{menu}</div>
<div>{menu2}</div>
</section>
);
}
class App extends Component<AppProps, AppState> {
constructor(props) {
super(props);
this.state = {
name: 'React'
};
}
render() {
return <Test />;
}
}
render(<App />, document.getElementById('root'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment