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
orvite
)
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
andmouseup
listeners are added ondocument
, notthis.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!