diff --git a/README.md b/README.md
index d5f93b553..97de9790a 100644
--- a/README.md
+++ b/README.md
@@ -94,6 +94,7 @@ https://github.com/user-attachments/assets/aab8d8e8-248f-46a1-919c-9b0601236ac1
- **[Cava](https://github.com/amnweb/yasb/wiki/(Widget)-Cava)**: Displays audio visualizer using Cava.
- **[Copilot](https://github.com/amnweb/yasb/wiki/(Widget)-Copilot)**: GitHub Copilot usage with a detailed menu showing statistics
- **[CPU](https://github.com/amnweb/yasb/wiki/(Widget)-CPU)**: Shows the current CPU usage.
+- **[Clipboard](https://github.com/amnweb/yasb/wiki/(Widget)-Clipboard)**: A native lightweight clipboard manager for YASB.
- **[Clock](https://github.com/amnweb/yasb/wiki/(Widget)-Clock)**: Displays the current time and date.
- **[Custom](https://github.com/amnweb/yasb/wiki/(Widget)-Custom)**: Create a custom widget.
- **[Github](https://github.com/amnweb/yasb/wiki/(Widget)-Github)**: Shows notifications from GitHub.
diff --git a/docs/widgets/(Widget)-Clipboard.md b/docs/widgets/(Widget)-Clipboard.md
new file mode 100644
index 000000000..aa4e3cef8
--- /dev/null
+++ b/docs/widgets/(Widget)-Clipboard.md
@@ -0,0 +1,161 @@
+# Clipboard Widget for YASB
+
+A lightweight clipboard manager for YASB that integrates directly with the native Windows Clipboard History (Win + V). This widget provides real-time access to your system's clip buffer without the need for heavy local storage or complex background monitoring.
+
+**Note for Users:** This widget requires the following Python packages to interact with Windows APIs:
+`pip install winrt-Windows.ApplicationModel.DataTransfer winrt-Windows.Foundation`
+
+## Features
+- **Native Windows Sync**: Syncs in real-time with your official Windows Clipboard History.
+- **Search**: Built-in real-time search bar to filter through your text-based history.
+- **History**: View your Clipboard history and delete a single history item or your entire history.
+- **Image Support**: Full support for previewing and re-copying images directly from the history list.
+- **Long text preview**: Hover over a copied long piece of text to display complete text preview.
+
+## Options
+
+| Option | Type | Default | Description |
+| :--- | :--- | :--- | :--- |
+| `type` | `string` | `yasb.clipboard.ClipboardWidget` | The widget class identifier. |
+| `label` | `string` | `\udb80\udd4d {clipboard}` | Primary label format. Supports `{clipboard}` token. |
+| `label_alt` | `string` | `CLIPBOARD` | Alternative label format (swapped on right-click). |
+| `max_length` | `integer` | `30` | Max characters to display in the bar before truncation. |
+| `max_history` | `integer` | `50` | Maximum number of history items to fetch from Windows. |
+| `class_name` | `string` | `""` | Additional CSS class for the widget container. |
+| `menu` | `dict` | (See Schema) | Configuration for the popup menu (blur, corners, alignment). |
+| `icons` | `dict` | (See Schema) | Custom icons for clipboard, clear, and search. |
+
+## Icons Configuration Defaults
+
+| Key | Default | Description |
+| :--- | :--- | :--- |
+| `clipboard` | `\udb80\udd4d` | Main widget icon used on the bar and in the "Copied!" flash. |
+| `clear` | `\uf1f8` | Global clear icon (Clears the system's unpinned history). |
+| `search_clear` | `\uf00d` | Icon used for general UI elements. |
+
+## Callbacks
+
+| Function | Description |
+| :--- | :--- |
+| `toggle_menu` | Opens/closes the clipboard history popup (Scheduled asynchronously). |
+| `toggle_label` | Switches display between `label` and `label_alt` on the bar. |
+
+---
+
+
+## Configuration Example
+
+```yaml
+ clipboard:
+ type: "yasb.clipboard.ClipboardWidget"
+ options:
+ label: "\udb80\udd4d"
+ label_alt: "CLIPBOARD"
+ max_length: 25
+ menu:
+ blur: false
+ round_corners: false
+ alignment: "right"
+ direction: "down"
+ callbacks:
+ on_left: "toggle_menu"
+ on_right: "toggle_label"
+```
+
+## Styling
+
+### Example CSS
+
+```css
+.clipboard-widget {
+ font-family: "JetBrainsMono Nerd Font", "Segoe UI Variable";
+}
+/* Widget on the bar */
+.clipboard-widget .label {
+ padding: 0 6px;
+ color: var(--mauve);
+}
+
+/* Main Popup Container */
+.clipboard-menu {
+ background-color: var(--bg-color1);
+ border: 1px solid var(--bg-color2);
+ border-radius: 10px;
+ padding: 8px;
+}
+
+/* Search Bar */
+.clipboard-menu .search-input {
+ background-color: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ border-radius: 6px;
+ padding: 6px 10px;
+ margin-bottom: 6px;
+ color: var(--text1);
+ font-size: 13px;
+}
+
+.clipboard-menu .search-input:focus {
+ border: 1px solid var(--blue);
+}
+
+/* Global Clear Button */
+.clipboard-menu .clear-button {
+ background-color: rgba(243, 139, 168, 0.1);
+ color: var(--red);
+ border-radius: 6px;
+ padding: 5px;
+ margin-bottom: 8px;
+ font-weight: bold;
+ font-size: 11px;
+}
+
+.clipboard-menu .clear-button:hover {
+ background-color: rgba(243, 139, 168, 0.2);
+}
+
+/* Scroll Area Styling */
+.clipboard-menu .scroll-area {
+ background: transparent;
+ border: none;
+}
+
+/* Individual Clipboard Items (Buttons) */
+.clipboard-menu .clipboard-item {
+ background-color: rgba(255, 255, 255, 0.03);
+ border: 1px solid transparent;
+ border-radius: 5px;
+ padding: 8px;
+ margin-bottom: 4px;
+ text-align: left;
+ color: var(--text1);
+ font-size: 12px;
+}
+
+.clipboard-menu .clipboard-item:hover {
+ background-color: rgba(255, 255, 255, 0.08);
+ border: 1px solid var(--bg-color2);
+}
+
+/* Image Item Specifics (if needed) */
+.clipboard-menu .clipboard-item [icon] {
+ margin-right: 8px;
+}
+
+/* Scrollbar Styling (Optional but looks better) */
+QScrollBar:vertical {
+ border: none;
+ background: transparent;
+ width: 4px;
+}
+
+QScrollBar::handle:vertical {
+ background: var(--bg-color2);
+ border-radius: 2px;
+}
+
+/* Styling for the temporary 'Copied!' flash */
+.clipboard-widget .label {
+ transition: all 0.2s ease-in-out;
+}
+```
diff --git a/src/core/validation/widgets/yasb/clipboard.py b/src/core/validation/widgets/yasb/clipboard.py
new file mode 100644
index 000000000..c21b127c3
--- /dev/null
+++ b/src/core/validation/widgets/yasb/clipboard.py
@@ -0,0 +1,59 @@
+from typing import Literal
+
+from pydantic import Field
+
+from core.validation.widgets.base_model import (
+ AnimationConfig,
+ CallbacksConfig,
+ CustomBaseModel,
+ KeybindingConfig,
+ PaddingConfig,
+ ShadowConfig,
+)
+
+
+class ClipboardMenuConfig(CustomBaseModel):
+ """Configuration for the clipboard popup menu."""
+
+ blur: bool = True
+ round_corners: bool = True
+ round_corners_type: Literal["normal", "small"] = "normal"
+ border_color: str = "System"
+ alignment: Literal["left", "right", "center"] = "right"
+ direction: Literal["up", "down"] = "down"
+ offset_top: int = 6
+ offset_left: int = 0
+ max_item_length: int = Field(default=50, ge=10, le=200)
+
+
+class ClipboardIconsConfig(CustomBaseModel):
+ """Configuration for clipboard widget icons."""
+
+ clipboard: str = "\udb80\udd4d"
+ clear: str = "\uf1f8"
+ search_clear: str = "\uf00d"
+
+
+class ClipboardCallbacksConfig(CallbacksConfig):
+ """Callbacks configuration with clipboard-specific defaults."""
+
+ on_left: str = "toggle_menu"
+ on_right: str = "toggle_label"
+
+
+class ClipboardConfig(CustomBaseModel):
+ """Main configuration model for the Clipboard widget."""
+
+ label: str = "\udb80\udd4d {clipboard}"
+ label_alt: str = "{clipboard}"
+ class_name: str = ""
+ max_length: int = Field(default=30, ge=5, le=100)
+ max_history: int = Field(default=50, ge=10, le=500)
+ menu: ClipboardMenuConfig = ClipboardMenuConfig()
+ icons: ClipboardIconsConfig = ClipboardIconsConfig()
+ animation: AnimationConfig = AnimationConfig()
+ container_padding: PaddingConfig = PaddingConfig()
+ label_shadow: ShadowConfig = ShadowConfig()
+ container_shadow: ShadowConfig = ShadowConfig()
+ keybindings: list[KeybindingConfig] = []
+ callbacks: ClipboardCallbacksConfig = ClipboardCallbacksConfig()
diff --git a/src/core/widgets/yasb/clipboard.py b/src/core/widgets/yasb/clipboard.py
new file mode 100644
index 000000000..f5a5b70e4
--- /dev/null
+++ b/src/core/widgets/yasb/clipboard.py
@@ -0,0 +1,302 @@
+import asyncio
+import logging
+
+from PyQt6.QtCore import Qt, QTimer
+from PyQt6.QtGui import QIcon, QPixmap
+from PyQt6.QtWidgets import (
+ QFrame,
+ QHBoxLayout,
+ QLabel,
+ QLineEdit,
+ QPushButton,
+ QScrollArea,
+ QSizePolicy,
+ QVBoxLayout,
+ QWidget,
+)
+from winrt.windows.applicationmodel.datatransfer import Clipboard, DataPackage, StandardDataFormats
+
+from core.utils.utilities import PopupWidget, add_shadow, build_widget_label
+from core.utils.widgets.animation_manager import AnimationManager
+from core.validation.widgets.yasb.clipboard import ClipboardConfig
+from core.widgets.base import BaseWidget
+
+
+class ClipboardWidget(BaseWidget):
+ """A clipboard manager widget that integrates with Windows Clipboard History."""
+
+ validation_schema = ClipboardConfig
+
+ def __init__(self, config: ClipboardConfig):
+ super().__init__(class_name=f"clipboard-widget {config.class_name}")
+ self.config = config
+ self._show_alt = False
+ self._menu = None
+
+ # Set up widget container layout
+ self._widget_container_layout = QHBoxLayout()
+ self._widget_container_layout.setSpacing(0)
+ self._widget_container_layout.setContentsMargins(
+ self.config.container_padding.left,
+ self.config.container_padding.top,
+ self.config.container_padding.right,
+ self.config.container_padding.bottom,
+ )
+
+ # Initialize container
+ self._widget_container = QFrame()
+ self._widget_container.setLayout(self._widget_container_layout)
+ self._widget_container.setProperty("class", "widget-container")
+ add_shadow(self._widget_container, self.config.container_shadow.model_dump())
+
+ # Add the container to the main widget layout
+ self.widget_layout.addWidget(self._widget_container)
+
+ # Build widget labels
+ build_widget_label(
+ self,
+ self.config.label.format(clipboard=""),
+ self.config.label_alt.format(clipboard=""),
+ self.config.label_shadow.model_dump(),
+ )
+
+ # Register callbacks
+ self.register_callback("toggle_menu", self.toggle_menu)
+ self.register_callback("toggle_label", self.toggle_label)
+
+ self.callback_left = self.config.callbacks.on_left
+ self.callback_right = self.config.callbacks.on_right
+ self.callback_middle = self.config.callbacks.on_middle
+
+ async def _fetch_and_show(self):
+ """Fetch clipboard history from Windows and show the popup menu."""
+ try:
+ history = await Clipboard.get_history_items_async()
+ items = []
+ if history.status.value == 0:
+ for item in list(history.items)[: self.config.max_history]:
+ content = item.content
+ entry = {"id": item.id, "type": "text", "data": None, "raw_item": item}
+
+ if content.contains(StandardDataFormats.text):
+ entry["data"] = await content.get_text_async()
+ items.append(entry)
+ elif content.contains(StandardDataFormats.bitmap):
+ try:
+ stream_ref = await content.get_bitmap_async()
+ stream = await stream_ref.open_read_async()
+ buffer = bytearray(stream.size)
+ await stream.read_async(buffer, stream.size, 0)
+
+ pixmap = QPixmap()
+ pixmap.loadFromData(buffer)
+ if not pixmap.isNull():
+ entry["data"] = pixmap
+ entry["raw"] = stream_ref
+ entry["type"] = "image"
+ items.append(entry)
+ except Exception:
+ continue
+
+ self._menu = ClipboardPopup(self, items, self.config)
+ self._menu.show_menu()
+ except Exception as e:
+ logging.error(f"Async Clipboard Error: {e}")
+
+ def toggle_menu(self):
+ """Toggle the clipboard history popup menu."""
+ try:
+ if self._menu and self._menu.isVisible():
+ self._menu.hide()
+ return
+ except RuntimeError:
+ self._menu = None
+
+ asyncio.create_task(self._fetch_and_show())
+
+ def toggle_label(self):
+ """Toggle between primary and alternate labels with animation."""
+ if self.config.animation.enabled:
+ AnimationManager.animate(self, self.config.animation.type, self.config.animation.duration)
+
+ self._show_alt = not self._show_alt
+ for widget in self._widgets:
+ widget.setVisible(not self._show_alt)
+ for widget in self._widgets_alt:
+ widget.setVisible(self._show_alt)
+
+ def set_system_clipboard(self, item):
+ """Set an item to the system clipboard."""
+ dp = DataPackage()
+ if item["type"] == "text":
+ dp.set_text(item["data"])
+ elif item["type"] == "image":
+ dp.set_bitmap(item["raw"])
+
+ Clipboard.set_content(dp)
+ Clipboard.flush()
+
+ # Provide visual feedback
+ self._flash_copied_message()
+
+ if self._menu:
+ self._menu.hide()
+
+ def _find_label_widget(self):
+ """Helper to find the QLabel created by build_widget_label."""
+ active_widgets = self._widgets_alt if self._show_alt else self._widgets
+ for widget in active_widgets:
+ if isinstance(widget, QLabel):
+ return widget
+ return None
+
+ def _flash_copied_message(self):
+ """Briefly show a 'Copied!' message on the widget label."""
+ label = self._find_label_widget()
+ if label:
+ icon = self.config.icons.clipboard
+ flash_text = f"{icon} Copied!"
+ label.setText(flash_text)
+ QTimer.singleShot(1500, self._revert_label)
+
+ def _revert_label(self):
+ """Revert the label to its original state."""
+ label = self._find_label_widget()
+ if label:
+ lbl = self.config.label_alt if self._show_alt else self.config.label
+ label.setText(lbl.format(clipboard=""))
+
+
+class ClipboardPopup(PopupWidget):
+ """Popup widget for displaying clipboard history."""
+
+ def __init__(self, parent_widget: ClipboardWidget, items: list, config: ClipboardConfig):
+ super().__init__(
+ parent_widget,
+ blur=config.menu.blur,
+ round_corners=config.menu.round_corners,
+ round_corners_type=config.menu.round_corners_type,
+ border_color=config.menu.border_color,
+ )
+ self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
+ self._parent_widget = parent_widget
+ self._all_items = items
+ self._icons = config.icons
+ self._menu_config = config.menu
+ self._init_ui()
+
+ def _init_ui(self):
+ """Initialize the popup UI."""
+ self.main_layout = QVBoxLayout(self)
+ self.setMinimumWidth(320)
+ self.setProperty("class", "clipboard-menu")
+
+ # Search bar
+ self.search_bar = QLineEdit()
+ self.search_bar.setProperty("class", "search-input")
+ self.search_bar.setPlaceholderText("Search history...")
+ self.search_bar.textChanged.connect(self._filter_items)
+ self.main_layout.addWidget(self.search_bar)
+
+ # Clear all button
+ clear_btn = QPushButton(f"{self._icons.clear} Clear All History")
+ clear_btn.setProperty("class", "clear-button")
+ clear_btn.clicked.connect(lambda: [Clipboard.clear_history(), self.close()])
+ self.main_layout.addWidget(clear_btn)
+
+ # Scroll area for items
+ self.scroll = QScrollArea()
+ self.scroll.setProperty("class", "scroll-area")
+ self.scroll.setWidgetResizable(True)
+ self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
+
+ self.container = QWidget()
+ self.container_layout = QVBoxLayout(self.container)
+ self.container_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
+ self.scroll.setWidget(self.container)
+ self.main_layout.addWidget(self.scroll)
+ self._render_items(self._all_items)
+
+ def _render_items(self, items):
+ """Render the clipboard items in the popup."""
+ # Clear existing items
+ while self.container_layout.count():
+ item = self.container_layout.takeAt(0)
+ widget = item.widget()
+ if widget:
+ widget.deleteLater()
+ else:
+ sub_layout = item.layout()
+ if sub_layout:
+ while sub_layout.count():
+ sub_item = sub_layout.takeAt(0)
+ if sub_item.widget():
+ sub_item.widget().deleteLater()
+ sub_layout.deleteLater()
+
+ if not items:
+ self.container_layout.addWidget(QLabel("No items match your search."))
+ return
+
+ max_item_len = self._menu_config.max_item_length
+
+ for item in items:
+ row = QHBoxLayout()
+
+ btn = QPushButton()
+ btn.setProperty("class", "clipboard-item")
+ btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
+
+ if item["type"] == "text":
+ clean = item["data"].replace("\n", " ").strip()
+ display = (clean[:max_item_len] + "..") if len(clean) > max_item_len else clean
+ btn.setText(display)
+ btn.setToolTip(item["data"])
+ else:
+ btn.setIcon(QIcon(item["data"]))
+ btn.setIconSize(item["data"].size().scaled(200, 80, Qt.AspectRatioMode.KeepAspectRatio))
+ btn.setText(" [Image]")
+
+ btn.clicked.connect(lambda _, i=item: self._parent_widget.set_system_clipboard(i))
+
+ del_btn = QPushButton(self._icons.search_clear)
+ del_btn.setFixedWidth(35)
+ del_btn.setStyleSheet("color: #e74c3c; font-weight: bold;")
+ del_btn.clicked.connect(lambda _, i=item: self._delete_item(i))
+
+ row.addWidget(btn)
+ row.addWidget(del_btn)
+ self.container_layout.addLayout(row)
+
+ def _delete_item(self, item_data):
+ """Remove a single item from Windows Clipboard History."""
+ try:
+ success = Clipboard.delete_item_from_history(item_data["raw_item"])
+ if not success:
+ logging.warning("Windows refused to delete the item.")
+ except AttributeError:
+ logging.error("Single item deletion is not supported by this WinRT package.")
+
+ # Refresh the UI
+ self.close()
+ asyncio.create_task(self._parent_widget._fetch_and_show())
+
+ def _filter_items(self, query):
+ """Filter clipboard items based on search query."""
+ filtered = []
+ for i in self._all_items:
+ if i["type"] == "image":
+ filtered.append(i)
+ elif query.lower() in i["data"].lower():
+ filtered.append(i)
+ self._render_items(filtered)
+
+ def show_menu(self):
+ """Show the popup menu positioned relative to the parent widget."""
+ self.show()
+ self.setPosition(
+ alignment=self._menu_config.alignment,
+ direction=self._menu_config.direction,
+ offset_left=self._menu_config.offset_left,
+ offset_top=self._menu_config.offset_top,
+ )