Application Menu and Context (Right Click) Menu using Svelte
Tags: javascript, webdev, svelte, css
Published: 2022-07-20 03:00:30

## Introduction

This is my first post at dev.to.

A week ago, I learned about Grid and Flexbox system of CSS3. First time learned about CSS was 13 years ago and not very much to learned after that. Frontend is not my thing and I had much time in the backend.

Actually, I'm a Civil Engineer, so web development is not my primary work for the last 10 years.

Last year, I discovered that Svelte can help you develop front end quickly. It was a major discovery, since I used to be struggle to learn React or Vue due to time constraint and complexity. On the other hand, Svelte and Sveltekit have become integrated nicely in my web development project.

On this web development project, I really want to create application menu and right-click context menu, like we usually see in desktop. I'm not very good at design, hence I need to re-learn CSS or CSS3, especially about grid system and/or flexbox.

To create this application menu and context menu, I believe flexbox is the best. But, I'm sure you know better than me and I believe you know other ways to achieve the same thing.

## Context Menu
You can see the actual context menu and its source code in [Svelte REPL here](https://svelte.dev/repl/6fb90919e24942b2b47d9ad154386b0c?version=3.49.0).

![Context menu right click example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k6nxmab6r3ewe1ms82ur.png)

There are several projects in Svelte REPL that has the same functionality. One of them is in [this link](https://svelte.dev/repl/3a33725c3adb4f57b46b597f9dade0c1?version=3.25.0).
It is nice and has been one of the inspiration to create my own version. I want a simpler version, since in my case I don't need much items in the menu.

One of the tricky part is to show the context menu properly when user click on the edge of browser, especially on the right side or on the bottom side of browser. If part of the displayed context menu will be shown outside the browser, as if there will be addition to height or width of the browser, then we need to rearrange the position of context menu. In this case, some math need to be incorporated to position the menu to the left or top from original position.

Other thing is you can change icons set to your taste. In this sample, I use Font Awesome from a CDN.

Please explore the code, since it is not very difficult once you can create your own version.

## Application Menu

You can see the actual context menu and its source code in [Svelte REPL here](https://svelte.dev/repl/3e17048619694bb6b9e9e9955fb00610?version=3.49.0).

![Application menu example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sbco1tiwflvlxbywczxw.png)
 
Application menu is what you have on desktop application. But, not much designer use them on the web. Usually this style of menu is used for web application that need many actions to a single web page. Google Sheet and Google Docs are examples that utilize them in their application. 

In my own version, you can listen to a function when user click the menu. Unfortunately, shortcut (e.g Ctrl +C) is just a demonstration and will not function as intended. Please bring your own implementation on this.

The important part of this application menu is how to handle the menu state to show and disappear. The menu should be shown when user click top level menu, but should disappear when user click outside the menu **OR** if the user click the top level menu once again. I consider this as difficult since this is a new thing for me.

I discovered [this article about clickOutside](https://svelte.dev/repl/8031c800d7e34fd692dd18174b514e4e?version=3.49.0) by lihautan help me learn more about action in Svelte. You can [watch his explanation in Youtube](https://www.youtube.com/watch?v=AzE9-6QcwmM).

In order to make the application menu works as expected, there are 2 conditions need to be true:
- if application menu (node ul) does not contain any click event(target), in other words menu is not clicked
- if top level (button) does not contain any click event(target), in other words top level menu is not click

```javascript
function clickOutside(node, params){
        function onClick(event){
            if (!node.contains(event.target)
                && !params.button.contains(event.target)){
                    params.f()
            } else {
                console.log("")
            }
        }

        window.addEventListener('click', onClick)
        ...
}  
```

```html
<button on:click={() => menuItem.visibleState = true}
bind:this={menuItem.buttonName}>{menuItem.displayText}
</button>
{#if menuItem.visibleState}
<ul class="secondmenu" use:clickOutside={
   {
      f: () => menuItem.visibleState = false,
      button: menuItem.buttonName
   }
}>
....
{/if}
```

We need to register event listener to the window when user click and open the menu. clickOutside will be an action to this application menu and handle what will happen if user click outside the menu.

## Conclusion

I hope you enjoy this post and please give comment if you have something better in your mind.