Build a dropdown component using Angular CDK
In this article, we’ll go through the process of creating a custom, reusable dropdown component with Angular CDK’s overlay module. The way it is consumed will resemble the Angular Material’s menu component.
Let’s go over the requirements
- Toggle dropdown when the button is clicked
- When clicked outside or on itself, the dropdown will be closed
Here is what the final result looks like,
Setup
Before we start, make sure to install Angular CDK.
npm install @angular/cdk
Also, add the following prebuilt style to your global stylesheet. By default that would be the styles.scss
file under src
directory.
@import '~@angular/cdk/overlay-prebuilt.css';
Overview
Our solution will have a similar approach to Angular Material menu component in the way it is consumed. That means we are going to use a directive that will get the reference for the dropdown it is going to control. Methods that open or close the dropdown will be written inside the directive.
dropdown-panel
is the interface that our dropdown component will implement. templateRef
holds the reference for the dropdown component template and closed
is the EventEmitter
that will emit when there is a click on the dropdown itself which then will be used for closing the dropdown.
In the end, this is how it will be used in the application
Toggle Dropdown
To kick things off, let’s create a directive called dropdownTriggerFor
. Two important things to mention here:
- Toggle dropdown method is bound to the host element’s click event
- Getting dropdown panel via
@Input
decorator so that we have access to the template reference of the dropdown and theEventEmitter
which we will subscribe to close the dropdown
Create an Overlay
The next step will be to create an overlay to which the dropdown will be attached. For that, we will use the Overlay service from Angular CDK and call the create method from the service.
Here is what we need to do,
- Create the overlay with
this.overlay.create({...})
method. - Using the dropdown panel we got from the
@Input
, create aTemplatePortal
. - Attach
TemplatePortal
to the overlay usingthis.overlayRef.attach(...)
method. - Start listening to the closing actions, so that we can close the dropdown when it emits a new value.
Now, the create
method takes a configuration object as a parameter to customize the overlay behaviour. Let’s go over some of its configurations.
- scrollStrategy: Configures the behaviour of the overlay during scrolling. Possible options are noop, reposition, block and close.
- flexibleConnectedTo: Pass in a connection origin for the overlay. This could be an element or element reference or any given (x, y) coordinates within the page. We want to connect the overlay to the button, that’s why we are passing
this.elementRef
as the connection origin. - withPositions: An array of positioning options for the overlay. Sorted from most to least desirable position. For brevity, I will pass in only one option that will render the dropdown underneath the button.
We have created an overlay, now let’s attach our dropdown template to it. We do so by creating a TemplatePortal
and pass in the templateRef
and the viewContainerRef
. Then we are going to attach created TemplatePortal
to the overlay using the attach
method.
Close Dropdown
Now that we took care of the opening part, let’s look into the scenarios in which we want to close the dropdown. As we stated in the requirements, it should be closed when there is a click on the outside or on itself. Clicks on the dropdown itself will be handled in the dropdown component, we will come to that in a second. Outside clicks can be captured with backdropClick
observable. Also, detachments
is an observable that emits when the overlay has been detached, that is something we should take into account. And last but not least, throw in the dropdown panel’s closed
event emitter in there as well. We will combine them all using merge
and subscribe to the resulting merged observable in the openDropdown
method.
To close the dropdown, we will call the destroyDropdown
method which will detach the overlay.
Create a Dropdown Component
The component is pretty simple. Just wrap ng-content
with a div and add some style to it. As mentioned before, we will use closed
here to emit a new value when there is a click on the dropdown itself.
We will also implement dropdown-panel
interface.
Done! 🎉
And that’s really it! We’ve seen how Angular CDK overlay can be used to create a reusable dropdown component and we are only scratching the surface here. CDK modules can help you develop many more kinds of components. Dialog, toast, drawer, tooltip, popover just to name a few.
Hope you find this article helpful. If you have any questions, don’t hesitate to drop a comment. 👋
Here is the complete source code,