The Challenge
Create a functional custom component (e.g. dropdown menu) using the Angular framework that matches the design exactly as shown below. Use the screenshot. No Figma available. šš¼
Guidelines
- Do not use premade UI libraries (such as Material, Bootstrap, Kendo, etc.).
- The code must be free of bugs and render correctly to pass the test.
- Please follow best practices and organize your code with appropriate structures. Use SCSS for styling.
- You are welcome to use the GSAP library to animate the dropdown menu if you wish.
- Icons (such as the āarrowā) can be handled in any way you prefer. Since you wonāt have the exact icon from the design, feel free to use a similar icon or handle it with a PNG.
- Some design details (such as colors, border radius, etc.) have been intentionally left out.
- Please use your best judgment and the methods you normally rely on to determine these implementation details.
Requirements
- The dropdown must utilize a two-way binding that allows you to change the selected option.
- If the external variable changes, the drop down should update to reflect the correct item.
- If the dropdown selection changes, the value of the external variable should also update.
- The dropdown should include a binding to set the placeholder label, which is displayed when no option is selected.
- It must also feature a binding to dynamically change the available selections in the dropdown list.
- When an option is selected in the dropdown, an event called
onSelection
should emit the identifier of the selected item. - The demo should demonstrate how this event is captured by the parent component.
- If there are more than five items in the list, a scrollbar should appear to allow users to scroll through the options (This part may be challenging due to the custom design for the scrollbar).
My First Draft
Instinctively, I felt something was already amiss. But I couldnāt put a pin on it quite yet. Lately, my headspace has been trending more towards React with the advent of version 19, NextJS aligning to that major release, and above all else this Astro world Iām currently in. Read Goodbye WordPress. Hello Astro! for more details.
I digress. My bad.
Back to the lecture at handā¦pivoting back to the bread and butter of Angular (IMO, two-way binding) my thought process was to kick out requirements 1-5 by way of a parent-child component setup to transmit data from OptionsMenuComponent
back into its parent, AppComponent
.
By way of a Reactive forms approach alongside @Input and @Output decorators at my side, I figured I had a shot at emitting the selected value back to AppComponent
and thatād be that!
So far so goodā¦
Thatās when my spidey senses finally kicked in and where I found myself in the crossroads. To this day, this Stack Overflow thread ages very well, How to style the option of an HTML select element?, in that you canāt style the actual HTML option element without intervention of a library.
Whoah, whoah, whoah! Slow down, sailor. Donāt go npm installing just yet. Youāre still at the mercy of the browser and operating system, so yeaā¦ummmā¦!@#$%^&*!
Letās end the component here and try something else.
My Renaissance
Building off of what I previously wrote I knew that Iād maintain the parent-to-child relationship using the previous decorators and that the road to requirements 6-8 went through customizing the āoptionā element.
Rather than being so committed to classic HTML form implementations using tags like form
, label
, input
, select
and textarea
I decided to run with div
elements paired with a button
element (heads upā¦I fracked in portions of the screenshot to make arrows) so I could better control the styling portion. Pairing that alongside some magic available from @angular/forms
, specifically ControlValueAccessor interface and NG_VALUE_ACCESSOR constant, bridged the gap between DOM elements to the Angular forms API, allowing me to keep parity to my previous efforts by emitting the value selected back to AppComponent
through the onSelection
method defined in that respective parent.
The Finale
Today, chefs, I prepared for you a coconut-currā¦I mean a functional dropdown menu using the Angular framework to match the design provided by the supplied screenshot.
I decided to save the previous component as an appetizer to illustrate the stark contrast in menu display between this and the respective entrƩe.
Conclusion
Outside of styling the improbable, what I found to be most interesting was dabbling with deferrable views on AppComponent
using blocks like @defer
, @loading
, @error
and @placeholder
. Was it necessary for a UI this small? Maybe. Maybe not. But entertaining the thought of using tools already stuffed inside of your back pocket are enticing, especially ones that may promote an initial reduction in bundle size.
Vibe Coding
Honestly, my mental cardio DIED when I couldnāt God mode the style palette for the original component. Thus, a sit down with GitHub CoPilot through VS Code was certainly used. That said, in order to keep Maverick from gun slinging a bit too much I stubbed in Angularās pseudo-class selector called :host
to target that component directly. Thatās more of a placeholder for Future Mark in the event he wants to refine the CSS in a different direction.
Itās not the plane, itās the pilot.
ā Top Gun: Maverick
About Options Service
I probably couldāve just mocked the data closer to the components but I wanted to fake an API call to play around with the modern-day way of dependency injection through inject()
to test out the concept of deferrable views. Big thanks to Mark Thompsenās Angular 17+ Fundamentals course on Frontend Masters to play around with the idea. Watch that, and itāll explain why I mucked with an asynchronous ngOnInit()
lifecycle hook.
Final Thoughts
Some of these tactics were courtesy of habits infused in a pre-renaissance ng-world, so a few more mental model updates are needed but itās been fascinating to see how Angular v17+ has come back to let me know that theyāve still got it going on as the one-stop shop for single-page web apps.
Have some fun and feel free to fork the repo or PR back to Angular 19 Custom Select Components Demo. Dependabot is enabled so dependencies are up-to-date!
View Demo
Thanks and Aloha! š¤š¾