Quickly and easily build a custom user menu for your application leveraging Clerk's hooks and methods and building on Radix primitives for a custom UI.
Important
<UserButton /> might be more flexible than you think! As of August 2024, you can now customize the component with custom menu items. Should you need even more customization, this post and part 2 are still here to help you build the experience you desire from scratch.
Clerk’s components were created with you in mind. Components do most of the functional work for you, allowing you to get your auth flows working in minutes, and support customization to fit your app’s style. That said, sometimes a component like the <UserButton /> doesn’t suit the needs of your application. The good news? Clerk provides hooks and functions that make building your custom UI components easy. Let’s take a quick look at how to create your custom user menu.
Note
Code samples are from @clerk/nextjs 4.27.2 and @radix-ui/react-dropdown-menu 2.0.6
The hardest part of building a custom user menu is often the dropdown menu itself. You need the button to trigger the menu opening, a way to close it, a way to track open/closed states, a way to handle ‘click off’ to close, logic to close if the user hits the Esc button, a way to handle keyboard input, and the list goes on. We’re going to save ourselves some time and use a great library while doing so. Radix provides world-class, accessible, unstyled primitives that you can use to quickly and efficiently build your UI. Let’s start by installing the primitive we need — the dropdown menu.
Once the installation finishes, let’s create the scaffolding for our new component. The following will be the foundation of the menu. The trigger will hold the User button that will open the menu, and each item will hold one of the menu entries. Remember that Radix Primitives are unstyled and there is no content so this will be blank.
The first content we will add is the User button. This will show that the user is logged in, and will be the trigger to open the menu. For the sake of this post we will assume that you have marked email as required in the Clerk Dashboard, in the User & Authentication → Email, Password, Username → Email section to ensure every user has an email. You could change this to a first name or username easily enough. Just make sure that whatever option you choose is something that will exist for all users, for the sake of rendering. You could also conditionally render different information depending on what the user has provided — show the first name if available; if not, show the email.
To build the button we will leverage the useUser() hook. This gives us access to information about the user, such as profile image, email, name, and more. We will also make sure that Clerk and the user have loaded, and that there is valid user data, before rendering the User button.
With the User button in place, we can now add Sign Out and Manage Account buttons. The useClerk() hook provides the two methods we will need for this — the signOut() method and the openUserProfile() method. The User Profile will open as a modal. You could, instead, mount the <UserProfile /> component to its own route, and then link it to the route. For the Sign Out button, we will also need to use the Next.js router to handle the redirect.
The custom button has now replicated the behavior of the <UserButton />, though it is very much still unstyled. We’re going to do one more thing — add one more menu entry to mimic expanding the menu. This will use the <Link /> component from Next.js to link to a fictional /subscriptions route.
Your new component is almost ready — it just needs some styling. Let’s add a little bit to get started. The code below is ready to drop right into your app, and then you can import the new <UserButton /> into your header.
Take a look at our Custom Flows documentation to explore more ways to customize your application using the many hooks and methods Clerks provides.
For more in-depth technical inquiries or to engage with our community, feel free to join our Discord. Stay in the loop with the latest Clerk features, enhancements, and sneak peeks by following our Twitter/X account, @ClerkDev. Your journey to seamless user management starts here!