wip; improve carousel docs

pull/1213/head
Cory LaViska 2023-02-23 16:50:18 -05:00
rodzic a526e8a956
commit c69db4919b
3 zmienionych plików z 346 dodań i 510 usunięć

Wyświetl plik

@ -2,10 +2,8 @@
[component-header:sl-carousel]
Carousels consist of optional navigation arrows to go backwards and forwards, as well as optional pagination indicators.
```html preview
<sl-carousel loop pagination navigation autoplay mouse-dragging>
<sl-carousel pagination navigation mouse-dragging loop>
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
@ -37,242 +35,276 @@ Carousels consist of optional navigation arrows to go backwards and forwards, as
/>
</sl-carousel-item>
</sl-carousel>
<sl-divider></sl-divider>
<div class="carousel-options">
<div class="carousel-options">
<sl-switch checked name="loop"> Loop </sl-switch>
<sl-switch checked name="navigation"> Show navigation </sl-switch>
<sl-switch checked name="pagination"> Show pagination </sl-switch>
<sl-switch checked name="autoplay"> Autoplay (3s) </sl-switch>
<sl-switch checked name="mouseDragging"> Mouse dragging </sl-switch>
</div>
<div class="carousel-options">
<sl-input type="number" label="Slides per page" name="slidesPerPage" value="1"></sl-input>
<sl-input type="number" label="Slides per move" name="slidesPerMove" value="1"></sl-input>
<sl-select label="Orientation" name="orientation" value="horizontal">
<sl-menu-item value="horizontal">Horizontal</sl-menu-item>
<sl-menu-item value="vertical">Vertical</sl-menu-item>
</sl-select>
</div>
</div>
<style>
sl-carousel {
--aspect-ratio: 3 / 2;
}
.carousel-options {
display: flex;
flex-wrap: wrap;
align-items: end;
gap: 1rem;
}
</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>
```
```jsx react
import { useReducer } from 'react';
import {
SlCarousel,
SlCarouselItem,
SlSwitch,
SlInput,
SlSelect,
SlMenuItem
} from '@shoelace-style/shoelace/dist/react';
import { SlCarousel, SlCarouselItem } 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/mountains.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.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/field.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.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>
</>
);
};
const App = () => (
<>
<SlCarousel pagination mouse-dragging>
<SlCarouselItem>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.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/field.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</SlCarouselItem>
</SlCarousel>
</>
);
```
<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
### Pagination
Setting the attribute `slides-per-view` is it possible to specify how many items are shown at a given time.
Using this feature, it may be also useful to advance multiple slides at once, even though not strictly necessary.
This can be done by using the `slides-per-move` attribute.
Use the `pagination` attribute to show the total number of slides and the current slide as a set of interactive dots.
```html preview
<sl-carousel class="multi-carousel" loop navigation pagination slides-per-page="3" slides-per-move="3">
<sl-carousel-item style="background: #204ed8;">Slide 1</sl-carousel-item>
<sl-carousel-item style="background: #be133d;">Slide 2</sl-carousel-item>
<sl-carousel-item style="background: #6e28d9;">Slide 3</sl-carousel-item>
<sl-carousel-item style="background: #c2420d;">Slide 4</sl-carousel-item>
<sl-carousel-item style="background: #4d7c0f;">Slide 5</sl-carousel-item>
<sl-carousel-item style="background: #4338cb;">Slide 6</sl-carousel-item>
<sl-carousel pagination>
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
src="/assets/examples/carousel/field.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</sl-carousel-item>
</sl-carousel>
```
### Navigation
Use the `navigation` attribute to show previous and next buttons.
```html preview
<sl-carousel navigation>
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
src="/assets/examples/carousel/field.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</sl-carousel-item>
</sl-carousel>
```
### Looping
By default, the carousel will not advanced beyond the first and last slides. You can change this behavior and force the carousel to "wrap" with the `loop` attribute.
```html preview
<sl-carousel loop navigation pagination>
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
src="/assets/examples/carousel/field.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</sl-carousel-item>
</sl-carousel>
```
### Autoplay
The carousel will automatically advance when the `autoplay` attribute is used. To change how long a slide is shown before advancing, set `autoplay-interval` to the desired number of milliseconds. For best results, use the `loop` attribute when autoplay is enabled. Note that autoplay will pause while the user interacts with the carousel.
```html preview
<sl-carousel autoplay loop pagination>
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
src="/assets/examples/carousel/field.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</sl-carousel-item>
</sl-carousel>
```
### Mouse Dragging
The carousel uses [scroll snap](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap) to position slides at various snap positions. This allows users to scroll through the slides very naturally, especially on touch devices. Unfortunately, desktop users won't be able to click and drag with a mouse, which can feel unnatural. Adding the `mouse-dragging` attribute can help with this.
This example is best demonstrated using a mouse. Try clicking and dragging the slide to move it. Then toggle the switch and try again.
```html preview
<div class="mouse-dragging">
<sl-carousel pagination>
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
src="/assets/examples/carousel/field.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</sl-carousel-item>
</sl-carousel>
<sl-divider></sl-divider>
<sl-switch>Enable mouse dragging</sl-switch>
</div>
<script>
const container = document.querySelector('.mouse-dragging');
const carousel = container.querySelector('sl-carousel');
const toggle = container.querySelector('sl-switch');
toggle.addEventListener('sl-change', () => {
carousel.toggleAttribute('mouse-dragging', toggle.checked);
});
</script>
```
### Multiple Slides Per View
The `slides-per-view` attribute makes it possible to display multiple slides at a time. You can also use the `slides-per-move` attribute to advance more than once slide at a time, if desired.
```html preview
<sl-carousel class="multi-carousel" navigation pagination slides-per-page="2" slides-per-move="2">
<sl-carousel-item style="background: var(--sl-color-red-200);">Slide 1</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-orange-200);">Slide 2</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-yellow-200);">Slide 3</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-green-200);">Slide 4</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-blue-200);">Slide 5</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-violet-200);">Slide 6</sl-carousel-item>
</sl-carousel>
```
@ -281,66 +313,73 @@ 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>
<SlCarouselItem style="background: var(--sl-color-red-200);">Slide 1</SlCarouselItem>
<SlCarouselItem style="background: var(--sl-color-orange-200);">Slide 2</SlCarouselItem>
<SlCarouselItem style="background: var(--sl-color-yellow-200);">Slide 3</SlCarouselItem>
<SlCarouselItem style="background: var(--sl-color-green-200);">Slide 4</SlCarouselItem>
<SlCarouselItem style="background: var(--sl-color-blue-200);">Slide 5</SlCarouselItem>
<SlCarouselItem style="background: var(--sl-color-violet-200);">Slide 6</SlCarouselItem>
</SlCarousel>
);
```
### Adding/removing slides
### Adding and Removing Slides
The content of the carousel can be changed by either appending or removing items, the carousel will update itself automatically.
The content of the carousel can be changed by appending or removing carousel items. The carousel will update itself automatically.
```html preview
<sl-carousel class="dynamic-carousel" pagination navigation>
<sl-carousel-item style="background: #204ed8;">Slide 1</sl-carousel-item>
<sl-carousel-item style="background: #be133d;">Slide 2</sl-carousel-item>
<sl-carousel-item style="background: #6e28d9;">Slide 3</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-red-200)">Slide 1</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-orange-200)">Slide 2</sl-carousel-item>
<sl-carousel-item style="background: var(--sl-color-yellow-200)">Slide 3</sl-carousel-item>
</sl-carousel>
<sl-divider></sl-divider>
<div class="carousel-options">
<sl-button id="dynamic-add">Add slide</sl-button>
<sl-button id="dynamic-remove">Remove slide</sl-button>
</div>
<style>
.dynamic-carousel {
--aspect-ratio: 3 / 2;
}
.dynamic-carousel ~ .carousel-options {
display: flex;
justify-content: center;
gap: var(--sl-spacing-x-small);
margin-top: var(--sl-spacing-large);
}
.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);
}
</style>
<script>
(() => {
const dynamicCarousel = document.querySelector('.dynamic-carousel');
const dynamicAdd = document.querySelector('#dynamic-add');
const dynamicRemove = document.querySelector('#dynamic-remove');
const rnd = (min, max) => Math.round(Math.random() * (max - min)) + min;
const getRandomColor = () => `rgb(${rnd(50, 150)}, ${rnd(50, 150)}, ${rnd(50, 150)})`;
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'violet'];
let colorIndex = 2;
const addSlide = () => {
const slide = document.createElement('sl-carousel-item');
const color = colors[++colorIndex % colors.length];
slide.innerText = `Slide ${dynamicCarousel.children.length + 1}`;
slide.style.setProperty('background', getRandomColor());
slide.style.setProperty('background', `var(--sl-color-${color}-200)`);
dynamicCarousel.appendChild(slide);
};
const removeSlide = () => {
const slide = dynamicCarousel.children[dynamicCarousel.children.length - 1];
slide.remove();
colorIndex--;
};
dynamicAdd.addEventListener('click', addSlide);
@ -358,6 +397,12 @@ const css = `
--aspect-ratio: 3 / 2;
}
.dynamic-carousel ~ .carousel-options {
display: flex;
justify-content: center;
margin-top: var(--sl-spacing-large);
}
.dynamic-carousel sl-carousel-item {
flex: 0 0 100%;
display: flex;
@ -370,9 +415,7 @@ const css = `
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 colors = ['red', 'orange', 'yellow', 'green', 'blue', 'violet'];
const addSlide = () => {
setSlides([...slides, getRandomColor()]);
@ -386,28 +429,31 @@ const App = () => {
<>
<SlCarousel className="dynamic-carousel" pagination navigation>
{slides.map((color, i) => (
<SlCarouselItem style={{ background: color }}>Slide {i}</SlCarouselItem>
<SlCarouselItem style={{ background: colors[i % colors.length }}>
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
### Vertical Scrolling
Setting the `orientation` attribute to `vertical`, will make the carousel laying out vertically, making it
possible for the user to scroll it up and down. In case of heterogeneous content, for example images of different sizes,
it's important to specify a predefined height to the carousel through CSS.
```html preview
<sl-carousel class="vertical" loop pagination orientation="vertical">
<sl-carousel class="vertical" pagination orientation="vertical">
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
@ -520,12 +566,12 @@ const App = () => (
);
```
### Aspect ratio
### Aspect Ratio
Use the `--aspect-ratio` custom property to customize the size of viewport in order to make it match a particular aspect ratio.
Use the `--aspect-ratio` custom property to customize the size of the carousel's viewport.
```html preview
<sl-carousel class="aspect-ratio" navigation pagination style="--aspect-ratio: 3 / 2">
<sl-carousel class="aspect-ratio" navigation pagination style="--aspect-ratio: 3/2">
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
@ -559,19 +605,20 @@ Use the `--aspect-ratio` custom property to customize the size of viewport in or
</sl-carousel>
<sl-divider></sl-divider>
<sl-select label="Aspect ratio" name="aspect" value="3 / 2">
<sl-menu-item value="1 / 1">1 / 1</sl-menu-item>
<sl-menu-item value="3 / 2">3 / 2</sl-menu-item>
<sl-menu-item value="16 / 9">16 / 9</sl-menu-item>
<sl-select label="Aspect ratio" name="aspect" value="3/2">
<sl-option value="1/1">1/1</sl-option>
<sl-option value="3/2">3/2</sl-option>
<sl-option value="16/9">16/9</sl-option>
</sl-select>
<script>
(() => {
const carousel = document.querySelector('sl-carousel.aspect-ratio');
const aspect = document.querySelector('sl-select[name="aspect"]');
const aspectRatio = document.querySelector('sl-select[name="aspect"]');
aspect.addEventListener('sl-change', () => {
carousel.style.setProperty('--aspect-ratio', aspect.value);
aspectRatio.addEventListener('sl-change', () => {
carousel.style.setProperty('--aspect-ratio', aspectRatio.value);
});
})();
</script>
@ -579,7 +626,7 @@ Use the `--aspect-ratio` custom property to customize the size of viewport in or
```jsx react
import { useState } from 'react';
import { SlCarousel, SlCarouselItem, SlDivider, SlSelect, SlMenuItem } from '@shoelace-style/shoelace/dist/react';
import { SlCarousel, SlCarouselItem, SlDivider, SlSelect, SlOption } from '@shoelace-style/shoelace/dist/react';
const App = () => {
const [aspectRatio, setAspectRatio] = useState('3/2');
@ -627,9 +674,9 @@ const App = () => {
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>
<SlOption value="1 / 1">1 / 1</SlOption>
<SlOption value="3 / 2">3 / 2</SlOption>
<SlOption value="16 / 9">16 / 9</SlOption>
</SlSelect>
<style>{css}</style>
@ -638,14 +685,12 @@ const App = () => {
};
```
### Scroll hint
### Scroll Hint
Use `--scroll-padding` to add inline padding in horizontal carousels and block padding in vertical carousels.
Setting a padding, will make the closest slides visible, suggesting to the user that there are items that can
be scrolled.
Use the `--scroll-hint` attribute to add inline padding in horizontal carousels and block padding in vertical carousels. Setting a padding will make the closest slides slightly visible, hinting that there are more items in the carousel.
```html preview
<sl-carousel class="scroll-hint" navigation pagination style="--scroll-padding: calc(var(--slide-gap) + 10%);">
<sl-carousel class="scroll-hint" pagination style="--scroll-hint: 10%;">
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
@ -677,20 +722,6 @@ be scrolled.
/>
</sl-carousel-item>
</sl-carousel>
<sl-divider></sl-divider>
<sl-range label="Size (%)" name="scroll-hint" value="5" min="0" max="15"></sl-range>
<script>
(() => {
const carousel = document.querySelector('sl-carousel.scroll-hint');
const scrollHint = document.querySelector('sl-range[name="scroll-hint"]');
scrollHint.addEventListener('sl-input', () => {
carousel.style.setProperty('--scroll-padding', `calc(var(--slide-gap) + ${scrollHint.value}%)`);
});
})();
</script>
```
```jsx react
@ -755,189 +786,9 @@ const App = () => {
};
```
### Custom layout
### Gallery Example
The appearance of the carousel can be easily customized through its slots or `part` attributes.
```html preview
<sl-carousel class="custom-layout" navigation pagination>
<sl-carousel-item>
<img
alt="The sun shines on the mountains and trees - Photo by Adam Kool on Unsplash"
src="/assets/examples/carousel/mountains.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A field of grass with the sun setting in the background - Photo by Sapan Patel on Unsplash"
src="/assets/examples/carousel/field.jpg"
/>
</sl-carousel-item>
<sl-carousel-item>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.jpg"
/>
</sl-carousel-item>
<sl-icon name="arrow-right" slot="next-icon"></sl-icon>
<sl-icon name="arrow-left" slot="previous-icon"></sl-icon>
</sl-carousel>
<style>
.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;
}
</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/mountains.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="A waterfall in the middle of a forest - Photo by Thomas Kelly on Unsplash"
src="/assets/examples/carousel/waterfall.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="The sun is setting over a lavender field - Photo by Leonard Cotte on Unsplash"
src="/assets/examples/carousel/sunset.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/field.jpg"
/>
</SlCarouselItem>
<SlCarouselItem>
<img
alt="A scenic view of a mountain with clouds rolling in - Photo by V2osk on Unsplash"
src="/assets/examples/carousel/valley.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
use `next()` or `previous()` to go respectively to the next or the previous slide.
When the active slide is changed, the `sl-slide-change` event is emitted providing the `index` of the slide.
Using the API is possible to extend the carousel, for example by syncing the active slide with a set of thumbnails, like in the example below.
The carousel has a robust API that makes it possible to extend and customize. This example syncs the active slide with a set of thumbnails, effectively creating a gallery-style carousel.
```html preview
<sl-carousel class="carousel-thumbnails" navigation loop>
@ -972,6 +823,7 @@ Using the API is possible to extend the carousel, for example by syncing the act
/>
</sl-carousel-item>
</sl-carousel>
<div class="thumbnails">
<div class="thumbnails__scroller">
<img alt="Thumbnail Photo by 1" class="thumbnails__image active" src="/assets/examples/carousel/mountains.jpg" />
@ -981,6 +833,7 @@ Using the API is possible to extend the carousel, for example by syncing the act
<img alt="Thumbnail Photo by 5" class="thumbnails__image" src="/assets/examples/carousel/valley.jpg" />
</div>
</div>
<style>
.carousel-thumbnails {
--slide-aspect-ratio: 3 / 2;
@ -1020,6 +873,7 @@ Using the API is possible to extend the carousel, for example by syncing the act
opacity: 1;
}
</style>
<script>
{
const carousel = document.querySelector('.carousel-thumbnails');

Wyświetl plik

@ -9,25 +9,20 @@ export default css`
--slide-gap: var(--sl-spacing-medium, 1rem);
--aspect-ratio: 16 / 9;
--scroll-padding: 0px;
--scroll-hint: 0px;
}
.carousel {
min-height: 100%;
min-width: 100%;
display: grid;
gap: var(--sl-spacing-medium);
grid-template-columns: min-content 1fr min-content;
grid-template-rows: 1fr min-content;
grid-template-areas:
'. slides .'
'. pagination .';
gap: var(--sl-spacing-medium);
align-items: center;
min-height: 100%;
min-width: 100%;
position: relative;
}
@ -40,19 +35,16 @@ export default css`
}
.carousel__slides {
height: 100%;
width: 100%;
grid-area: slides;
display: grid;
height: 100%;
width: 100%;
align-items: center;
justify-items: center;
overflow: auto;
overscroll-behavior-x: contain;
scrollbar-width: none;
aspect-ratio: calc(var(--aspect-ratio) * var(--slides-per-page));
--slide-size: calc((100% - (var(--slides-per-page) - 1) * var(--slide-gap)) / var(--slides-per-page));
@ -69,11 +61,9 @@ export default css`
grid-auto-columns: var(--slide-size);
grid-auto-rows: 100%;
column-gap: var(--slide-gap);
scroll-snap-type: x mandatory;
scroll-padding-inline: var(--scroll-padding);
padding-inline: var(--scroll-padding);
scroll-padding-inline: var(--scroll-hint);
padding-inline: var(--scroll-hint);
}
.carousel__slides--vertical {
@ -81,11 +71,9 @@ export default css`
grid-auto-columns: 100%;
grid-auto-rows: var(--slide-size);
row-gap: var(--slide-gap);
scroll-snap-type: y mandatory;
scroll-padding-block: var(--scroll-padding);
padding-block: var(--scroll-padding);
scroll-padding-block: var(--scroll-hint);
padding-block: var(--scroll-hint);
}
.carousel__slides--dragging,
@ -104,7 +92,6 @@ export default css`
.carousel__navigation {
grid-area: navigation;
display: contents;
font-size: var(--sl-font-size-x-large);
}

Wyświetl plik

@ -17,7 +17,7 @@ import styles from './carousel.styles';
import type { CSSResultGroup } from 'lit';
/**
* @summary Carousels display an arbitrary number of slides along a horizontal or vertical axis.
* @summary Carousels display an arbitrary number of content slides along a horizontal or vertical axis.
*
* @since 2.0
* @status experimental
@ -42,7 +42,7 @@ import type { CSSResultGroup } from 'lit';
*
* @cssproperty --slide-gap - The space between each slide.
* @cssproperty --aspect-ratio - The aspect ratio of each slide.
* @cssproperty --scroll-padding - The amount of padding to apply to the scroll area. Useful to make adjacent slides
* @cssproperty --scroll-hint - The amount of padding to apply to the scroll area. Useful to make adjacent slides
* visible.
*/
@customElement('sl-carousel')
@ -320,22 +320,17 @@ export default class SlCarousel extends ShoelaceElement {
${map(range(pagesCount), index => {
const isActive = index === currentPage;
return html`
<span role="presentation">
<button
@click="${() => this.goToSlide(index * slidesPerPage)}"
aria-selected="${isActive ? 'true' : 'false'}"
aria-label="${this.localize.term('goToCarouselSlide', index + 1, pagesCount)}"
role="tab"
part="
pagination-item
${isActive ? 'pagination-item--active' : ''}
"
class="${classMap({
'carousel__pagination-item': true,
'carousel__pagination-item--active': isActive
})}"
></button>
</span>
<button
part="pagination-item ${isActive ? 'pagination-item--active' : ''}"
class="${classMap({
'carousel__pagination-item': true,
'carousel__pagination-item--active': isActive
})}"
aria-selected="${isActive ? 'true' : 'false'}"
aria-label="${this.localize.term('goToCarouselSlide', index + 1, pagesCount)}"
role="tab"
@click="${() => this.goToSlide(index * slidesPerPage)}"
></button>
`;
})}
</nav>