mirror of
https://github.com/shoelace-style/shoelace.git
synced 2026-01-12 11:09:13 +00:00
chore: add react examples
This commit is contained in:
@@ -97,6 +97,166 @@ Carousels consist of optional navigation arrows to go backwards and forwards, as
|
||||
</script>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { useReducer } from 'react';
|
||||
import {
|
||||
SlCarousel,
|
||||
SlCarouselItem,
|
||||
SlSwitch,
|
||||
SlInput,
|
||||
SlSelect,
|
||||
SlMenuItem
|
||||
} from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const css = `
|
||||
sl-carousel {
|
||||
--aspect-ratio: 3 / 2;
|
||||
}
|
||||
|
||||
.carousel-options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: end;
|
||||
gap: 1rem;
|
||||
}
|
||||
`;
|
||||
|
||||
const App = () => {
|
||||
const [state, updateState] = useReducer(
|
||||
(state, event) => {
|
||||
console.log(event);
|
||||
},
|
||||
{
|
||||
loop: true,
|
||||
pagination: true,
|
||||
navigation: true,
|
||||
autoplay: true,
|
||||
mouseDragging: true,
|
||||
slidesPerPage: 1,
|
||||
slidesPerMove: 1,
|
||||
orientation: 'horizontal'
|
||||
}
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<SlCarousel
|
||||
loop={state.loop}
|
||||
pagination={state.pagination}
|
||||
navigation={state.navigation}
|
||||
autoplay={state.autoplay}
|
||||
mouseDragging={state.mouseDragging}
|
||||
>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
|
||||
src="/assets/examples/carousel/adam-kool-ndN00KmbJ1c-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
|
||||
src="/assets/examples/carousel/thomas-kelley-JoH60FhTp50-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
|
||||
src="/assets/examples/carousel/leonard-cotte-c1Jp-fo53U8-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
|
||||
src="/assets/examples/carousel/sapan-patel-i9Q9bc-WgfE-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
|
||||
src="/assets/examples/carousel/v2osk-1Z2niiBPg5A-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
</SlCarousel>
|
||||
<SlDivider></SlDivider>
|
||||
<div className="carousel-options">
|
||||
<div className="carousel-options">
|
||||
<SlSwitch checked name="loop" value={state.loop} onSlChange={updateState}>
|
||||
Loop
|
||||
</SlSwitch>
|
||||
<SlSwitch checked name="navigation" value={state.navigation} onSlChange={updateState}>
|
||||
Show navigation
|
||||
</SlSwitch>
|
||||
<SlSwitch checked name="pagination" value={state.pagination} onSlChange={updateState}>
|
||||
Show pagination
|
||||
</SlSwitch>
|
||||
<SlSwitch checked name="autoplay" value={state.autoplay} onSlChange={updateState}>
|
||||
Autoplay (3s)
|
||||
</SlSwitch>
|
||||
<SlSwitch checked name="mouseDragging" value={state.mouseDragging} onSlChange={updateState}>
|
||||
Mouse dragging
|
||||
</SlSwitch>
|
||||
</div>
|
||||
<div className="carousel-options">
|
||||
<SlInput
|
||||
type="number"
|
||||
label="Slides per page"
|
||||
name="slidesPerPage"
|
||||
value={state.slidesPerPage}
|
||||
onSlChange={updateState}
|
||||
/>
|
||||
<SlInput
|
||||
type="number"
|
||||
label="Slides per move"
|
||||
name="slidesPerMove"
|
||||
value={state.slidesPerMove}
|
||||
onSlChange={updateState}
|
||||
/>
|
||||
<SlSelect
|
||||
label="Orientation"
|
||||
name="orientation"
|
||||
value="horizontal"
|
||||
value={state.orientation}
|
||||
onSlChange={updateState}
|
||||
>
|
||||
<SlMenuItem value="horizontal">Horizontal</SlMenuItem>
|
||||
<SlMenuItem value="vertical">Vertical</SlMenuItem>
|
||||
</SlSelect>
|
||||
</div>
|
||||
</div>
|
||||
<style>{css}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
<script>
|
||||
(() => {
|
||||
const options = document.querySelector('.carousel-options');
|
||||
const carousel = document.querySelector('sl-carousel');
|
||||
const loop = options.querySelector('sl-switch[name="loop"]');
|
||||
const navigation = options.querySelector('sl-switch[name="navigation"]');
|
||||
const pagination = options.querySelector('sl-switch[name="pagination"]');
|
||||
const autoplay = options.querySelector('sl-switch[name="autoplay"]');
|
||||
const mouseDragging = options.querySelector('sl-switch[name="mouseDragging"]');
|
||||
const slidesPerMove = options.querySelector('sl-input[name="slidesPerMove"]');
|
||||
const slidesPerPage = options.querySelector('sl-input[name="slidesPerPage"]');
|
||||
const orientation = options.querySelector('sl-select[name="orientation"]');
|
||||
|
||||
loop.addEventListener('sl-change', () => (carousel.loop = loop.checked));
|
||||
navigation.addEventListener('sl-change', () => (carousel.navigation = navigation.checked));
|
||||
pagination.addEventListener('sl-change', () => (carousel.pagination = pagination.checked));
|
||||
autoplay.addEventListener('sl-change', () => (carousel.autoplay = autoplay.checked));
|
||||
slidesPerMove.addEventListener('sl-change', () => (carousel.slidesPerMove = slidesPerMove.valueAsNumber));
|
||||
slidesPerPage.addEventListener('sl-change', () => (carousel.slidesPerPage = slidesPerPage.valueAsNumber));
|
||||
orientation.addEventListener('sl-change', () => (carousel.orientation = orientation.value));
|
||||
mouseDragging.addEventListener('sl-change', () => (carousel.mouseDragging = mouseDragging.checked));
|
||||
|
||||
document.addEventListener('sl-slide-change', e => {
|
||||
console.log('Slide changed:', e.detail);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
## Examples
|
||||
|
||||
### Multiple slides per view
|
||||
@@ -116,6 +276,21 @@ This can be done by using the `slides-per-move` attribute.
|
||||
</sl-carousel>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlCarousel, SlCarouselItem } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => (
|
||||
<SlCarousel class="multi-carousel" loop navigation pagination slides-per-page="3" slides-per-move="3">
|
||||
<SlCarouselItem style="background: #204ed8;">Slide 1</SlCarouselItem>
|
||||
<SlCarouselItem style="background: #be133d;">Slide 2</SlCarouselItem>
|
||||
<SlCarouselItem style="background: #6e28d9;">Slide 3</SlCarouselItem>
|
||||
<SlCarouselItem style="background: #c2420d;">Slide 4</SlCarouselItem>
|
||||
<SlCarouselItem style="background: #4d7c0f;">Slide 5</SlCarouselItem>
|
||||
<SlCarouselItem style="background: #4338cb;">Slide 6</SlCarouselItem>
|
||||
</SlCarousel>
|
||||
);
|
||||
```
|
||||
|
||||
### Adding/removing slides
|
||||
|
||||
The content of the carousel can be changed by either appending or removing items, the carousel will update itself automatically.
|
||||
@@ -174,6 +349,57 @@ The content of the carousel can be changed by either appending or removing items
|
||||
</script>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { useState } from 'react';
|
||||
import { SlCarousel, SlCarouselItem } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const css = `
|
||||
.dynamic-carousel {
|
||||
--aspect-ratio: 3 / 2;
|
||||
}
|
||||
|
||||
.dynamic-carousel sl-carousel-item {
|
||||
flex: 0 0 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: white;
|
||||
font-size: var(--sl-font-size-2x-large);
|
||||
}
|
||||
`;
|
||||
|
||||
const App = () => {
|
||||
const [slides, setSlides] = useState(['#204ed8', '#be133d', '#6e28d9']);
|
||||
|
||||
const rnd = (min, max) => Math.round(Math.random() * (max - min)) + min;
|
||||
const getRandomColor = () => `rgb(${rnd(50, 150)}, ${rnd(50, 150)}, ${rnd(50, 150)})`;
|
||||
|
||||
const addSlide = () => {
|
||||
setSlides([...slides, getRandomColor()]);
|
||||
};
|
||||
|
||||
const removeSlide = () => {
|
||||
setSlides(slides.slice(0, -1));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SlCarousel className="dynamic-carousel" pagination navigation>
|
||||
{slides.map((color, i) => (
|
||||
<SlCarouselItem style={{ background: color }}>Slide {i}</SlCarouselItem>
|
||||
))}
|
||||
</SlCarousel>
|
||||
<SlDivider />
|
||||
<div className="carousel-options">
|
||||
<SlButton onClick={addSlide}>Add slide</SlButton>
|
||||
<SlButton onClick={removeSlide}>Remove slide</SlButton>
|
||||
</div>
|
||||
<style>{css}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Vertical scrolling
|
||||
|
||||
Setting the `orientation` attribute to `vertical`, will make the carousel laying out vertically, making it
|
||||
@@ -233,6 +459,67 @@ it's important to specify a predefined height to the carousel through CSS.
|
||||
</style>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlCarousel, SlCarouselItem } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const css = `
|
||||
.vertical {
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.vertical::part(base) {
|
||||
grid-template-areas: 'slides slides pagination';
|
||||
}
|
||||
|
||||
.vertical::part(pagination) {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.vertical::part(navigation) {
|
||||
transform: rotate(90deg);
|
||||
display: flex;
|
||||
}
|
||||
`;
|
||||
|
||||
const App = () => (
|
||||
<>
|
||||
<SlCarousel className="vertical" loop pagination orientation="vertical">
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
|
||||
src="/assets/examples/carousel/adam-kool-ndN00KmbJ1c-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
|
||||
src="/assets/examples/carousel/thomas-kelley-JoH60FhTp50-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
|
||||
src="/assets/examples/carousel/leonard-cotte-c1Jp-fo53U8-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
|
||||
src="/assets/examples/carousel/sapan-patel-i9Q9bc-WgfE-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
|
||||
src="/assets/examples/carousel/v2osk-1Z2niiBPg5A-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
</SlCarousel>
|
||||
<style>{css}</style>
|
||||
</>
|
||||
);
|
||||
```
|
||||
|
||||
### Aspect ratio
|
||||
|
||||
Use the `--aspect-ratio` custom property to customize the size of viewport in order to make it match a particular aspect ratio.
|
||||
@@ -290,6 +577,67 @@ Use the `--aspect-ratio` custom property to customize the size of viewport in or
|
||||
</script>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { useState } from 'react';
|
||||
import { SlCarousel, SlCarouselItem, SlDivider, SlSelect, SlMenuItem } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => {
|
||||
const [aspectRatio, setAspectRatio] = useState('3/2');
|
||||
|
||||
return (
|
||||
<>
|
||||
<SlCarousel className="aspect-ratio" navigation pagination style={{ '--aspect-ratio': aspectRatio }}>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
|
||||
src="/assets/examples/carousel/adam-kool-ndN00KmbJ1c-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
|
||||
src="/assets/examples/carousel/thomas-kelley-JoH60FhTp50-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
|
||||
src="/assets/examples/carousel/leonard-cotte-c1Jp-fo53U8-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
|
||||
src="/assets/examples/carousel/sapan-patel-i9Q9bc-WgfE-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
|
||||
src="/assets/examples/carousel/v2osk-1Z2niiBPg5A-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
</SlCarousel>
|
||||
|
||||
<SlDivider />
|
||||
|
||||
<SlSelect
|
||||
label="Aspect ratio"
|
||||
name="aspect"
|
||||
value={aspectRatio}
|
||||
onSlChange={event => setAspectRatio(event.target.value)}
|
||||
>
|
||||
<SlMenuItem value="1 / 1">1 / 1</SlMenuItem>
|
||||
<SlMenuItem value="3 / 2">3 / 2</SlMenuItem>
|
||||
<SlMenuItem value="16 / 9">16 / 9</SlMenuItem>
|
||||
</SlSelect>
|
||||
|
||||
<style>{css}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Scroll hint
|
||||
|
||||
Use `--scroll-padding` to add inline padding in horizontal carousels and block padding in vertical carousels.
|
||||
@@ -345,6 +693,68 @@ be scrolled.
|
||||
</script>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { useState } from 'react';
|
||||
import { SlCarousel, SlCarouselItem, SlDivider, SlRange } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const App = () => {
|
||||
const [scrollPadding, setScrollPadding] = useState(10);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SlCarousel
|
||||
className="scroll-hint"
|
||||
navigation
|
||||
pagination
|
||||
style={{ '--aspect-ratio': `calc(var(--slide-gap) + ${scrollPadding}%)` }}
|
||||
>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
|
||||
src="/assets/examples/carousel/adam-kool-ndN00KmbJ1c-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
|
||||
src="/assets/examples/carousel/thomas-kelley-JoH60FhTp50-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
|
||||
src="/assets/examples/carousel/leonard-cotte-c1Jp-fo53U8-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
|
||||
src="/assets/examples/carousel/sapan-patel-i9Q9bc-WgfE-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
|
||||
src="/assets/examples/carousel/v2osk-1Z2niiBPg5A-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
</SlCarousel>
|
||||
|
||||
<SlDivider />
|
||||
|
||||
<SlRange
|
||||
label="Size (%)"
|
||||
value="5"
|
||||
min="0"
|
||||
max="15"
|
||||
onSlChange={event => setScrollPadding(event.target.valueAsNumber)}
|
||||
/>
|
||||
<style>{css}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
### Custom layout
|
||||
|
||||
The appereance of the carousel can be easly customized through its slots or `part` attributes.
|
||||
@@ -431,6 +841,95 @@ The appereance of the carousel can be easly customized through its slots or `par
|
||||
</style>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { SlCarousel, SlCarouselItem } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const css = `
|
||||
.custom-layout::part(base) {
|
||||
grid-template-areas:
|
||||
'slides slides slides'
|
||||
'slides slides slides';
|
||||
}
|
||||
|
||||
.custom-layout::part(pagination) {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
padding: var(--sl-spacing-large);
|
||||
background: linear-gradient(0deg, rgba(0, 0, 0, 0.8) 5%, rgba(0, 0, 0, 0.2) 75%, rgba(0, 0, 0, 0) 100%);
|
||||
}
|
||||
|
||||
.custom-layout::part(pagination-item) {
|
||||
height: 5px;
|
||||
width: var(--sl-spacing-large);
|
||||
border-radius: var(--sl-border-radius-pill);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.custom-layout::part(pagination-item--active) {
|
||||
background-color: var(--sl-color-primary-400);
|
||||
width: var(--sl-spacing-x-large);
|
||||
}
|
||||
|
||||
.custom-layout::part(navigation-button) {
|
||||
margin: var(--sl-spacing-large);
|
||||
border-radius: var(--sl-border-radius-circle);
|
||||
font-weight: var(--sl-font-weight-bold);
|
||||
color: var(--sl-color-neutral-1000);
|
||||
background: var(--sl-color-neutral-0);
|
||||
opacity: 0.6;
|
||||
transition: var(--sl-transition-medium) opacity;
|
||||
}
|
||||
|
||||
.custom-layout::part(navigation-button):focus,
|
||||
.custom-layout::part(navigation-button):hover {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
const App = () => (
|
||||
<>
|
||||
<SlCarousel className="custom-layout" pagination navigation>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
|
||||
src="/assets/examples/carousel/adam-kool-ndN00KmbJ1c-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
|
||||
src="/assets/examples/carousel/thomas-kelley-JoH60FhTp50-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
|
||||
src="/assets/examples/carousel/leonard-cotte-c1Jp-fo53U8-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
|
||||
src="/assets/examples/carousel/sapan-patel-i9Q9bc-WgfE-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
|
||||
src="/assets/examples/carousel/v2osk-1Z2niiBPg5A-unsplash.jpg"
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
|
||||
<SlIcon name="arrow-right" slot="next-icon"></SlIcon>
|
||||
<SlIcon name="arrow-left" slot="previous-icon"></SlIcon>
|
||||
</SlCarousel>
|
||||
<style>{css}</style>
|
||||
</>
|
||||
);
|
||||
```
|
||||
|
||||
### Gallery example
|
||||
|
||||
The carousel has a set of API with which is possible to interact programmatically, for example it is possible to
|
||||
@@ -483,36 +982,21 @@ Using the API is possible to extend the carousel, for exmaple by syncing the act
|
||||
<img
|
||||
alt="Thumbnail Photo by 2"
|
||||
class="thumbnails__image"
|
||||
Jeff
|
||||
King
|
||||
on
|
||||
Unsplash
|
||||
src="/assets/examples/carousel/thomas-kelley-JoH60FhTp50-unsplash.jpg"
|
||||
/>
|
||||
<img
|
||||
alt="Thumbnail Photo by 3"
|
||||
class="thumbnails__image"
|
||||
Leonard
|
||||
Cotte
|
||||
on
|
||||
Unsplash
|
||||
src="/assets/examples/carousel/leonard-cotte-c1Jp-fo53U8-unsplash.jpg"
|
||||
/>
|
||||
<img
|
||||
alt="Thumbnail Photo by 4"
|
||||
class="thumbnails__image"
|
||||
Lukasz
|
||||
Szmigiel
|
||||
on
|
||||
Unsplash
|
||||
src="/assets/examples/carousel/sapan-patel-i9Q9bc-WgfE-unsplash.jpg"
|
||||
/>
|
||||
<img
|
||||
alt="Thumbnail Photo by 5"
|
||||
class="thumbnails__image"
|
||||
V2osk
|
||||
on
|
||||
Unsplash
|
||||
src="/assets/examples/carousel/v2osk-1Z2niiBPg5A-unsplash.jpg"
|
||||
/>
|
||||
</div>
|
||||
@@ -587,4 +1071,124 @@ Using the API is possible to extend the carousel, for exmaple by syncing the act
|
||||
</script>
|
||||
```
|
||||
|
||||
```jsx react
|
||||
import { useRef } from 'react';
|
||||
import { SlCarousel, SlCarouselItem, SlDivider, SlRange } from '@shoelace-style/shoelace/dist/react';
|
||||
|
||||
const css = `
|
||||
.carousel-thumbnails {
|
||||
--slide-aspect-ratio: 3 / 2;
|
||||
}
|
||||
|
||||
.thumbnails {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.thumbnails__scroller {
|
||||
display: flex;
|
||||
gap: var(--sl-spacing-small);
|
||||
overflow-x: auto;
|
||||
scrollbar-width: none;
|
||||
scroll-behavior: smooth;
|
||||
scroll-padding: var(--sl-spacing-small);
|
||||
}
|
||||
|
||||
.thumbnails__scroller::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.thumbnails__image {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
object-fit: cover;
|
||||
|
||||
opacity: 0.3;
|
||||
will-change: opacity;
|
||||
transition: 250ms opacity;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.thumbnails__image.active {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
const images = [
|
||||
{
|
||||
src: '/assets/examples/carousel/adam-kool-ndN00KmbJ1c-unsplash.jpg',
|
||||
alt: 'The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash'
|
||||
},
|
||||
{
|
||||
src: '/assets/examples/carousel/thomas-kelley-JoH60FhTp50-unsplash.jpg',
|
||||
alt: 'A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash'
|
||||
},
|
||||
{
|
||||
src: '/assets/examples/carousel/leonard-cotte-c1Jp-fo53U8-unsplash.jpg',
|
||||
alt: 'The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash'
|
||||
},
|
||||
{
|
||||
src: '/assets/examples/carousel/sapan-patel-i9Q9bc-WgfE-unsplash.jpg',
|
||||
alt: 'A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash'
|
||||
},
|
||||
{
|
||||
src: '/assets/examples/carousel/v2osk-1Z2niiBPg5A-unsplash.jpg',
|
||||
alt: 'A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash'
|
||||
}
|
||||
];
|
||||
|
||||
const App = () => {
|
||||
const carouselRef = useRef();
|
||||
const thumbnailsRef = useRef();
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
const thumbnails = Array.from(thumbnailsRef.current.querySelectorAll('.thumbnails__image'));
|
||||
|
||||
thumbnails[currentSlide]..scrollIntoView({
|
||||
block: 'nearest'
|
||||
});
|
||||
}, [currentSlide]);
|
||||
|
||||
const handleThumbnailClick = (index) => {
|
||||
carouselRef.current.goToSlide(index);
|
||||
}
|
||||
|
||||
const handleSlideChange = (event) => {
|
||||
const slideIndex = e.detail.index;
|
||||
setCurrentSlide(slideIndex);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SlCarousel className="carousel-thumbnails" navigation loop onSlSlideChange={handleSlideChange}>
|
||||
{images.map({ src, alt }) => (
|
||||
<SlCarouselItem>
|
||||
<img
|
||||
alt={alt}
|
||||
src={src}
|
||||
/>
|
||||
</SlCarouselItem>
|
||||
)}
|
||||
</SlCarousel>
|
||||
|
||||
<div class="thumbnails">
|
||||
<div class="thumbnails__scroller">
|
||||
{images.map({ src, alt }, i) => (
|
||||
<img
|
||||
alt={`Thumbnail Photo by ${i + 1}`}
|
||||
className={`thumbnails__image ${i === currentSlide ? 'active' : ''}`}
|
||||
onCLick={() => handleThumbnailClick(i)}
|
||||
src={src}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<style>{css}</style>
|
||||
</>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
[component-metadata:sl-carousel]
|
||||
|
||||
Reference in New Issue
Block a user