Welcome to HyFun Tech, where creativity meets technology. Specializing in web design, development, and digital marketing, we help businesses thrive online through innovative solutions that captivate audiences and drive growth.

Lit is an awesome library that helps developers build fast, lightweight web components with a minimal learning curve. But sometimes, when you’re trying to build something cool — like a retro-style draggable UI — things just don’t go as planned.

In this post, we’ll walk through how to build a retro draggable web component using Lit and tackle common problems that might break your code along the way.


🎯 Goal: Create a Draggable Web Component with Retro Style

We’re aiming for:

  • A draggable box (like a vintage Win95 window 🫯)
  • Styled with pixel fonts and borders
  • Built entirely using Lit

🧱 Step 1: Setup Your Project

You’ll need:

  • Node.js
  • A simple development server (like lite-server or vite)

Install Lit

npm install lit

Set up your file structure:

/retro-draggable
  ├── index.html
  ├── draggable-box.js
  └── styles.css

🧑‍💻 Step 2: Create the Web Component

Here’s a basic structure of draggable-box.js:

import { LitElement, html, css } from 'lit';

class DraggableBox extends LitElement {
  static styles = css`
    .window {
      width: 200px;
      height: 150px;
      background: #c0c0c0;
      border: 2px solid black;
      position: absolute;
      top: 50px;
      left: 50px;
      font-family: 'Courier New', monospace;
      cursor: move;
      box-shadow: 2px 2px black;
    }

    .title-bar {
      background: navy;
      color: white;
      padding: 4px;
      font-size: 14px;
    }
  `;

  constructor() {
    super();
    this.dragging = false;
    this.offset = { x: 0, y: 0 };
  }

  firstUpdated() {
    const windowBox = this.shadowRoot.querySelector('.window');
    const titleBar = this.shadowRoot.querySelector('.title-bar');

    titleBar.addEventListener('mousedown', (e) => {
      this.dragging = true;
      this.offset = {
        x: e.clientX - windowBox.offsetLeft,
        y: e.clientY - windowBox.offsetTop
      };
    });

    document.addEventListener('mousemove', (e) => {
      if (this.dragging) {
        windowBox.style.left = `${e.clientX - this.offset.x}px`;
        windowBox.style.top = `${e.clientY - this.offset.y}px`;
      }
    });

    document.addEventListener('mouseup', () => {
      this.dragging = false;
    });
  }

  render() {
    return html`
      <div class="window">
        <div class="title-bar">Retro Window</div>
        <div class="content">Drag me around!</div>
      </div>
    `;
  }
}

customElements.define('draggable-box', DraggableBox);

📄 Step 3: Hook It Up in index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Retro Draggable</title>
    <script type="module" src="./draggable-box.js"></script>
  </head>
  <body>
    <draggable-box></draggable-box>
  </body>
</html>

🛠️ Common Issues and Fixes

❌ Component doesn’t move

  • Problem: You’re adding event listeners inside the shadow DOM, but trying to drag from the document.
  • Fix: Make sure the mousemove and mouseup listeners are added on document, not this.shadowRoot.

❌ Style isn’t applying

  • Problem: Using external styles or forgetting static styles.
  • Fix: Use static styles = css\`;` inside your component or use scoped styles inside shadow DOM.

❌ Component not showing

  • Problem: Forgot to define the custom element.
  • Fix: Add customElements.define('draggable-box', DraggableBox); at the end of your JS.

✨ Bonus: Add Retro Pixel Fonts

Include a pixel font for the ultimate retro vibes.

<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">

Then update your CSS:

font-family: 'Press Start 2P', monospace;

✅ Final Touch

Now you have a clean, draggable, retro-styled window component made with Lit!


🧠 Wrapping Up

Lit makes building web components feel natural and fun. If you ran into issues while making a draggable element, chances are it’s something small like event scope, custom element definition, or styling within shadow DOM.

Need the full code or a working demo? Let me know — happy to share it on GitHub or CodePen!

Leave a Reply

Your email address will not be published. Required fields are marked *