diff --git a/carousel/README.md b/carousel/README.md
new file mode 100644
index 0000000..10e2da2
--- /dev/null
+++ b/carousel/README.md
@@ -0,0 +1,35 @@
+# Carousel
+
+Carousels display a set of items, such as images or cards, that can be scrolled horizontally.
+
+## Example Usage
+
+```html
+
+
+
+
+ Card 1
+
+
+ Card 2
+
+
+ Card 3
+
+
+```
+
+## CSS Variables
+
+### ``
+* `--md-carousel-gap`: Gap between carousel items (default: `8px`)
+* `--md-carousel-padding`: Padding around the carousel scroll container (default: `0`)
+
+### ``
+* `--md-carousel-item-width`: Width of the carousel item (default: `300px`)
+* `--md-carousel-item-shape`: Border radius of the carousel item (default: `28px`)
diff --git a/carousel/carousel-item.js b/carousel/carousel-item.js
new file mode 100644
index 0000000..d21708d
--- /dev/null
+++ b/carousel/carousel-item.js
@@ -0,0 +1,38 @@
+import { html, LitElement, css } from 'lit'
+
+/**
+ * A Material Design carousel item component.
+ *
+ * @element md-carousel-item
+ */
+export class CarouselItem extends LitElement {
+ render() {
+ return html`
+
+
+
+ `
+ }
+
+ static styles = css`
+ :host {
+ display: inline-block;
+ flex-shrink: 0;
+ scroll-snap-align: start;
+ /* default size for demo, can be overridden */
+ width: var(--md-carousel-item-width, 300px);
+ }
+
+ .item-container {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ box-sizing: border-box;
+ /* Usually border radius of 28px or 24px in MD3 depending on variant */
+ border-radius: var(--md-carousel-item-shape, 28px);
+ overflow: hidden;
+ }
+ `
+}
+
+customElements.define('md-carousel-item', CarouselItem)
diff --git a/carousel/carousel.js b/carousel/carousel.js
new file mode 100644
index 0000000..7d1568c
--- /dev/null
+++ b/carousel/carousel.js
@@ -0,0 +1,53 @@
+import { html, LitElement, css } from 'lit'
+
+/**
+ * A Material Design carousel component.
+ *
+ * @element md-carousel
+ */
+export class Carousel extends LitElement {
+ static properties = {
+ ariaLabel: { type: String, attribute: 'aria-label' },
+ }
+
+ constructor() {
+ super()
+ this.ariaLabel = 'Carousel'
+ }
+
+ render() {
+ return html`
+
+
+
+ `
+ }
+
+ static styles = css`
+ :host {
+ display: block;
+ /* Carousel styling based on Material Design 3 */
+ /* Note: specific width/height may need to be configurable */
+ }
+
+ .scroll-container {
+ display: flex;
+ gap: var(--md-carousel-gap, 8px);
+ overflow-x: auto;
+ scroll-snap-type: x mandatory;
+ overscroll-behavior-x: contain;
+
+ /* Hide scrollbar for cleaner look, but keep functionality */
+ scrollbar-width: none; /* Firefox */
+ -ms-overflow-style: none; /* IE and Edge */
+
+ padding: var(--md-carousel-padding, 0);
+ }
+
+ .scroll-container::-webkit-scrollbar {
+ display: none; /* Chrome, Safari and Opera */
+ }
+ `
+}
+
+customElements.define('md-carousel', Carousel)
diff --git a/demo/index.html b/demo/index.html
index bb1a109..67452d4 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -58,6 +58,9 @@
import 'material/snackbar/snackbar.js'
import 'material/app/bar.js'
import 'material/progress/progress.js'
+ import 'material/carousel/carousel.js'
+ import 'material/carousel/carousel-item.js'
+ import 'material/card/card.js'
import './components/expressive-component.js'
@@ -178,7 +181,36 @@ Inputs
- Progress
+
+ Carousel
+
+
+
+ Item 1
+
+
+
+
+ Item 2
+
+
+
+
+ Item 3
+
+
+
+
+ Item 4
+
+
+
+
+ Item 5
+
+
+
+Progress