Angular Signals Code Lab Drag & Drop Letters
After looking over some purely decorative CSS in the Angular Signals code lab sample application, I dug around elsewhere in the source code for interesting things to learn. The next item that caught my attention was the "keyboard" where we drag-and-dropped letters to create our decoder. How was this done?
Inside the HTML template code, I found an attribute cdkDropListGroup
on the keyboard container. A web search pointed me to the Angular CDK (Control Development Kit.) Angular CDK is a library that packages many common web app behaviors we can use in our own custom controls, one of them being drag-and-drop as used in the Angular Signals sample app. The CDK is apparently under the umbrella of Angular Material, which has a set of fully implemented app controls implemented to the Material Design specification. Many of them use the CDK for their own implementation.
Drag-and-drop behavior in Angular CDK is very flexible and has many options for configuring behavior. Such flexibility and options unfortunately also meant it's easy for a beginner to get lost. I'm thankful I have the Angular Signals code lab cipher app. It lets me look over a very specific simple use of CDK drag-and-drop.
Here's an excerpt of the HTML template for the cipher keyboard in file cipher.ts
, stripped of everything unrelated to drag-and-drop.
<div class="cipher-wrapper" cdkDropListGroup>
<div class="key-container">
<letter-key
*ngFor="let l of this.cipher.alphabet"
cdkDropList
cdkDropListSortingDisabled
[cdkDropListData]="l"/>
</div>
<div class="guess-container"
cdkDropList
cdkDropListSortingDisabled>
<letter-guess
*ngFor="let l of this.cipher.unsolvedAlphabet()"
cdkDrag
[cdkDragData]="l"
(cdkDragDropped)="drop($event)">
<div class="placeholder" *cdkDragPlaceholder></div>
</letter-guess>
</div>
</div>
It has two containers, one for a list of custom control letter-key
and and another for a list of letter-guess
. Drag-and-drop is all encapsulated here in cipher.ts
, there's nothing in either of those two controls concerning drag-and-drop.
Uniting these two containers is a div with cdkDropListGroup
which associates all child cdkDropList
elements together. This allows us to drag individual letter-guess
(tagged with cdkDrag
) from one cdkDropList
onto the sibling cdkDropList
of letter-key
. These properties are enough to let Angular CDK know how to respond to pointer input events to manipulate these elements. All the app has to do is register a cdkDragDropped
listener for when a cdkDrag
element is dropped into a cdkDropList
.
I poked around the code looking for how a letter-guess
sits in the key-container
after it has been dropped into the right location. The answer is: it doesn't, that's just an illusion. When a letter is dropped into the correct location, it is removed from the list returned by this.cipher.unsolvedalphabet()
. Meaning that particular letter-guess
I had been dragging disappears. The letter-key
I had dragged it onto, however, will pick up a new CSS class and change its appearance to look as if the letter-guess
stayed in that location.
I had to spend some time flipping between looking at source code and looking at CDK drag-and-drop API documentation. But once I made that time investment, I could understand how this app utilized the library. Once understood, I'm impressed at how little work is required in an Angular app to pick up very complex behavior from Angular CDK.

I look forward to leveraging this capability in my own projects in the future. Before that, though, I can try using Angular signals in my Compass practice app.