# BottomSheet

*Category:* Components
*Section:* Application
*Source:* https://uikit.developers.rio.cloud/#/components/bottomSheet
*Captured:* 2026-04-27T14:57:11.981Z

The TimedBottomSheet is a wrapper component for the BottomSheet that allows to control it's visibility via timers and to use the localStorage to save user interaction for handling it's visibility.

## BottomSheet

### Example: Example 1

This demonstrates a small bottom sheet use case on desktop. This can be used for providing additional information, upselling, feedback etc.
Trigger small BottomSheet

#### React (tsx)

```tsx
import React, { useState } from 'react';

import BottomSheet from '@rio-cloud/rio-uikit/BottomSheet';

export default () => {
    const [showBottomSheet, setShowBottomSheet] = useState(false);
    return (
        <div>
            <p className='margin-top-0'>
                This demonstrates a small bottom sheet use case on <b>desktop.</b> This can be used for providing
                additional information, upselling, feedback etc.
            </p>
            <button className='btn btn-primary' type='button' onClick={() => setShowBottomSheet(true)}>
                Trigger small BottomSheet
            </button>

            <BottomSheet
                show={showBottomSheet}
                width={400}
                onClose={() => setShowBottomSheet(false)}
                detach
                bodyClassName='padding-25 margin-right-25'
            >
                {content}
            </BottomSheet>
        </div>
    );
};

const content = (
    <React.Fragment>
        <div>Hi there! Would you be interested in the latest features?</div>
        <div className='btn-toolbar margin-top-15 display-flex justify-content-end'>
            <button type='button' className='btn btn-link btn-sm'>
                No, thanks
            </button>
            <button type='button' className='btn btn-default btn-sm'>
                <span className='rioglyph rioglyph-heart' />
                Yes, show me more
            </button>
        </div>
    </React.Fragment>
);
```

#### HTML (html)

```html
<div>
    <p class="margin-top-0">This demonstrates a small bottom sheet use case on <b>desktop.</b> This can be used for providing additional information, upselling, feedback etc.</p>
    <button class="btn btn-primary" type="button">Trigger small BottomSheet</button>
</div>
```

#### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| show | boolean | false | Set the visibility of the bottom sheet. The component is already mounted and just moved offscreen. |
| onClose | (isShown: boolean) => void | — | Callback for when the sheet closes. |
| width | number \| string | — | The width of the bottom sheet. This is useful for desktop when not using the entire screen width. When no width is given it will take the width of the content and maximum 100% of the screen. So it this case you might want to apply a max-width-xxx via className to control it better. |
| height | number \| string | — | The height of the bottom sheet. If no height is given, the height is automatically calculated from the content. |
| title | string \| ReactNode | — | The title content shown in the header. If no title is given, the bottom sheet header is not shown. |
| showCloseButton | boolean | true | Defines whether or not the close button is shown. |
| showMaximizeButton | boolean | false | Defines whether or not the maximize button in the header is shown. |
| onHeightChange | VoidFunction | () => {} | The callback function triggered when the maximize button is clicked and the height changes. |
| detach | boolean | false | Set to true to detach the bottom sheet from the left side and the bottom and create a little offset. |
| detachOffset | number | 15 | Defines the amount of pixels for the sheet. |
| hasBackdrop | boolean | false | Set to true to render a modal like backdrop to emphasize the bottom sheet. |
| onBackdropClick | VoidFunction | () => {} | Callback function triggered when the backdrop is clicked. Usually used to close the bottom sheet. |
| bodyRef | MutableRefObject<HTMLDivElement \| null> | — | A react ref added to the bottom sheet body. |
| bodyClassName | string | — | Additional classes to be set on the body element. |
| className | string | — | Additional classes to be set on the wrapping element. |

### Example: Example 2

This demonstrates a bottom sheet use case on mobile. This can be used for providing additional information on mobile instead of using a sidebar, onboarding, alternative for dialogs etc.
Note This example does not make sense on desktop with wider screens. Handle responsive modes and use a dialog or sidebar on desktop instead.
Trigger mobile BottomSheet

#### React (tsx)

```tsx
import { useState, useRef, useEffect } from 'react';
import { throttle } from 'es-toolkit/function';

import BottomSheet from '@rio-cloud/rio-uikit/BottomSheet';
import useElementSize from '@rio-cloud/rio-uikit/useElementSize';

export default () => {
    const [showBottomSheet, setShowBottomSheet] = useState(false);
    const [listHeight, setListHeight] = useState(300);

    const sheetBodyRef = useRef<HTMLDivElement>(null);
    const [_, bodyHeight] = useElementSize(sheetBodyRef);

    // To adjust the height of the list elements according to the current height of the bottom sheet body,
    // we use the element size hook and check for the body height. When it changes, we set the height of the
    // list throttled to skip some renderings in between
    useEffect(() => {
        // Note that we need to subtract the height of the menu from the sheet body height since it fix.
        // In this example we assume roughly a height of 130 pixels for the nav pills menu
        const navPillsHeight = 130;
        const throttledHeightChange = throttle(newHeight => setListHeight(newHeight - navPillsHeight), 1000);

        if (bodyHeight) {
            throttledHeightChange(bodyHeight);
        }
    }, [bodyHeight]);

    return (
        <div>
            <p className='margin-top-0'>
                {'This demonstrates a bottom sheet use case on '}
                <b>{'mobile. '}</b>
                {'This can be used for providing additional information on mobile instead of using a sidebar, '}
                onboarding, alternative for dialogs etc.
            </p>
            <p>
                <span className='label label-info label-condensed margin-right-5'>Note</span>
                {'This example does not make sense on desktop with wider screens. '}
                Handle responsive modes and use a dialog or sidebar on desktop instead.
            </p>
            <button className='btn btn-primary' type='button' onClick={() => setShowBottomSheet(true)}>
                Trigger mobile BottomSheet
            </button>

            <BottomSheet
                show={showBottomSheet}
                onClose={() => setShowBottomSheet(false)}
                title={
                    <div>
                        <div className='text-medium'>Lorem ipsum dolor sit amet</div>
                        <div className='text-size-14 text-color-darker'>consectetur adipiscing elit</div>
                    </div>
                }
                height={500}
                showMaximizeButton
                className='max-width-800'
                bodyRef={sheetBodyRef}
            >
                <div>
                    <div className='padding-15'>
                        <ul className='nav nav-pills nav-pills-filled nav-justified'>
                            <li className='active shadow-default'>
                                <span>First tab</span>
                            </li>
                            <li>
                                <span>Second tab with longer content</span>
                            </li>
                            <li>
                                <span>Third tab</span>
                            </li>
                        </ul>
                    </div>
                    <div
                        className='padding-15 padding-top-0 padding-bottom-25 overflow-scroll'
                        style={{ height: listHeight }}
                    >
                        <div>Content for Pill 1 ...</div>
                        <ul className='panel-list margin-top-10 margin-bottom-0'>
                            {Array.from({ length: 15 }, (_, index) => (
                                <li key={index}>
                                    <div className='text-medium'>{`${index + 1}. Lorem ipsum dolor sit amet`}</div>
                                    <div>
                                        {'consectetur adipiscing elit. In pharetra dui eget massa efficitur aliquam '}
                                        condimentum in felis.
                                    </div>
                                </li>
                            ))}
                        </ul>
                    </div>
                </div>
            </BottomSheet>
        </div>
    );
};
```

#### HTML (html)

```html
<div>
    <p class="margin-top-0">This demonstrates a bottom sheet use case on <b>mobile. </b>This can be used for providing additional information on mobile instead of using a sidebar, onboarding, alternative for dialogs etc.</p>
    <p>
        <span class="label label-info label-condensed margin-right-5">Note</span>This example does not make sense on desktop with wider screens. Handle responsive modes and use a dialog or sidebar on desktop instead.
    </p>
    <button class="btn btn-primary" type="button">Trigger mobile BottomSheet</button>
</div>
```

#### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| show | boolean | false | Set the visibility of the bottom sheet. The component is already mounted and just moved offscreen. |
| onClose | (isShown: boolean) => void | — | Callback for when the sheet closes. |
| width | number \| string | — | The width of the bottom sheet. This is useful for desktop when not using the entire screen width. When no width is given it will take the width of the content and maximum 100% of the screen. So it this case you might want to apply a max-width-xxx via className to control it better. |
| height | number \| string | — | The height of the bottom sheet. If no height is given, the height is automatically calculated from the content. |
| title | string \| ReactNode | — | The title content shown in the header. If no title is given, the bottom sheet header is not shown. |
| showCloseButton | boolean | true | Defines whether or not the close button is shown. |
| showMaximizeButton | boolean | false | Defines whether or not the maximize button in the header is shown. |
| onHeightChange | VoidFunction | () => {} | The callback function triggered when the maximize button is clicked and the height changes. |
| detach | boolean | false | Set to true to detach the bottom sheet from the left side and the bottom and create a little offset. |
| detachOffset | number | 15 | Defines the amount of pixels for the sheet. |
| hasBackdrop | boolean | false | Set to true to render a modal like backdrop to emphasize the bottom sheet. |
| onBackdropClick | VoidFunction | () => {} | Callback function triggered when the backdrop is clicked. Usually used to close the bottom sheet. |
| bodyRef | MutableRefObject<HTMLDivElement \| null> | — | A react ref added to the bottom sheet body. |
| bodyClassName | string | — | Additional classes to be set on the body element. |
| className | string | — | Additional classes to be set on the wrapping element. |

### Example: Example 3

This demonstrates a bottom sheet use case on mobile. It demonstrates a bottom sheet for smartphones to perform an action.
Trigger mobile BottomSheet

#### React (tsx)

```tsx
import { useState } from 'react';

import BottomSheet from '@rio-cloud/rio-uikit/BottomSheet';
import Switch from '@rio-cloud/rio-uikit/Switch';
import RadioButton from '@rio-cloud/rio-uikit/RadioButton';
import Button from '@rio-cloud/rio-uikit/Button';

export default () => {
    const [showBottomSheet, setShowBottomSheet] = useState(false);

    return (
        <div>
            <p className='margin-top-0'>
                This demonstrates a bottom sheet use case on <b>mobile.</b> It demonstrates a bottom sheet for
                smartphones to perform an action.
            </p>
            <button className='btn btn-primary' type='button' onClick={() => setShowBottomSheet(true)}>
                Trigger mobile BottomSheet
            </button>

            <BottomSheet
                show={showBottomSheet}
                onClose={() => setShowBottomSheet(false)}
                title='New Collection'
                hasBackdrop
                onBackdropClick={() => console.log('foobar')}
                className='max-width-400'
            >
                <div className='padding-15'>
                    <div className='display-flex justify-content-between align-items-center margin-top-15 margin-bottom-15 padding-15 bg-lightest rounded'>
                        <div>
                            <div className='text-medium text-size-16 text-color-darker'>Private</div>
                            <div className='text-size-12 text-color-dark margin-top-5'>
                                Only viewable by people you invite
                            </div>
                        </div>
                        <Switch checked />
                    </div>

                    <label className='margin-left-10 margin-top-20 margin-bottom-0'>Contribution Settings</label>
                    <div className='display-flex justify-content-between align-items-center margin-top-15 margin-bottom-15 padding-15 bg-lightest rounded'>
                        <div>
                            <div className='text-medium text-size-16 text-color-darker'>Controlled</div>
                            <div className='text-size-12 text-color-dark margin-top-5'>
                                Only allow members that are contributors to add content
                            </div>
                        </div>
                        <RadioButton name='radioGroup' id='onlyMember' defaultChecked />
                    </div>
                    <div className='display-flex justify-content-between align-items-center margin-top-15 margin-bottom-15 padding-15 bg-lightest rounded'>
                        <div>
                            <div className='text-medium text-size-16 text-color-darker'>Open</div>
                            <div className='text-size-12 text-color-dark margin-top-5'>
                                Allow all members to add content
                            </div>
                        </div>
                        <RadioButton name='radioGroup' id='open' />
                    </div>

                    <Button
                        bsStyle='primary'
                        bsSize={Button.LG}
                        block
                        className='margin-top-25'
                        onClick={() => setShowBottomSheet(false)}
                    >
                        Create Collection
                    </Button>
                </div>
            </BottomSheet>
        </div>
    );
};
```

#### HTML (html)

```html
<div>
    <p class="margin-top-0">This demonstrates a bottom sheet use case on <b>mobile.</b> It demonstrates a bottom sheet for smartphones to perform an action.</p>
    <button class="btn btn-primary" type="button">Trigger mobile BottomSheet</button>
</div>
```

#### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| show | boolean | false | Set the visibility of the bottom sheet. The component is already mounted and just moved offscreen. |
| onClose | (isShown: boolean) => void | — | Callback for when the sheet closes. |
| width | number \| string | — | The width of the bottom sheet. This is useful for desktop when not using the entire screen width. When no width is given it will take the width of the content and maximum 100% of the screen. So it this case you might want to apply a max-width-xxx via className to control it better. |
| height | number \| string | — | The height of the bottom sheet. If no height is given, the height is automatically calculated from the content. |
| title | string \| ReactNode | — | The title content shown in the header. If no title is given, the bottom sheet header is not shown. |
| showCloseButton | boolean | true | Defines whether or not the close button is shown. |
| showMaximizeButton | boolean | false | Defines whether or not the maximize button in the header is shown. |
| onHeightChange | VoidFunction | () => {} | The callback function triggered when the maximize button is clicked and the height changes. |
| detach | boolean | false | Set to true to detach the bottom sheet from the left side and the bottom and create a little offset. |
| detachOffset | number | 15 | Defines the amount of pixels for the sheet. |
| hasBackdrop | boolean | false | Set to true to render a modal like backdrop to emphasize the bottom sheet. |
| onBackdropClick | VoidFunction | () => {} | Callback function triggered when the backdrop is clicked. Usually used to close the bottom sheet. |
| bodyRef | MutableRefObject<HTMLDivElement \| null> | — | A react ref added to the bottom sheet body. |
| bodyClassName | string | — | Additional classes to be set on the body element. |
| className | string | — | Additional classes to be set on the wrapping element. |

### Example: Example 4

This demonstrates a bottom sheet use case on mobile. It demonstrates a bottom sheet for an example of how you could do onboarding on smartphones.
Trigger mobile onboarding BottomSheet

#### React (tsx)

```tsx
import { useState } from 'react';

import imageSliderDemoService1 from '../../demoService/assets/imageSliderDemoService1.png';
import imageSliderDemoService2 from '../../demoService/assets/imageSliderDemoService2.png';
import imageSliderDemoService3 from '../../demoService/assets/imageSliderDemoService3.png';
import imageSliderDemoService4 from '../../demoService/assets/imageSliderDemoService4.png';

import BottomSheet from '@rio-cloud/rio-uikit/BottomSheet';
import Carousel from '@rio-cloud/rio-uikit/Carousel';

export default () => {
    const [showBottomSheet, setShowBottomSheet] = useState(false);
    return (
        <div>
            <p className='margin-top-0'>
                {'This demonstrates a bottom sheet use case on '}
                <b>{'mobile. '}</b>
                It demonstrates a bottom sheet for an example of how you could do onboarding on smartphones.
            </p>
            <button className='btn btn-primary' type='button' onClick={() => setShowBottomSheet(true)}>
                Trigger mobile onboarding BottomSheet
            </button>

            <BottomSheet
                show={showBottomSheet}
                onClose={() => setShowBottomSheet(false)}
                hasBackdrop
                className='max-width-400'
            >
                <div className='padding-25 padding-bottom-10 margin-top-20'>
                    <Carousel className='arrow-color-dark show-indicators offset-indicators shadow-default'>
                        <Carousel.Item>
                            <div className='panel panel-default margin-bottom-0 overflow-hidden'>
                                <img className='img-responsive' src={imageSliderDemoService1} />
                            </div>
                        </Carousel.Item>

                        <Carousel.Item>
                            <div className='panel panel-default margin-bottom-0 overflow-hidden'>
                                <img className='img-responsive' src={imageSliderDemoService2} />
                            </div>
                        </Carousel.Item>

                        <Carousel.Item>
                            <div className='panel panel-default margin-bottom-0 overflow-hidden'>
                                <img className='img-responsive' src={imageSliderDemoService3} />
                            </div>
                        </Carousel.Item>

                        <Carousel.Item>
                            <div className='panel panel-default margin-bottom-0 overflow-hidden'>
                                <img className='img-responsive' src={imageSliderDemoService4} />
                            </div>
                        </Carousel.Item>
                    </Carousel>
                </div>
            </BottomSheet>
        </div>
    );
};
```

#### HTML (html)

```html
<div>
    <p class="margin-top-0">This demonstrates a bottom sheet use case on <b>mobile. </b>It demonstrates a bottom sheet for an example of how you could do onboarding on smartphones.</p>
    <button class="btn btn-primary" type="button">Trigger mobile onboarding BottomSheet</button>
</div>
```

#### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| show | boolean | false | Set the visibility of the bottom sheet. The component is already mounted and just moved offscreen. |
| onClose | (isShown: boolean) => void | — | Callback for when the sheet closes. |
| width | number \| string | — | The width of the bottom sheet. This is useful for desktop when not using the entire screen width. When no width is given it will take the width of the content and maximum 100% of the screen. So it this case you might want to apply a max-width-xxx via className to control it better. |
| height | number \| string | — | The height of the bottom sheet. If no height is given, the height is automatically calculated from the content. |
| title | string \| ReactNode | — | The title content shown in the header. If no title is given, the bottom sheet header is not shown. |
| showCloseButton | boolean | true | Defines whether or not the close button is shown. |
| showMaximizeButton | boolean | false | Defines whether or not the maximize button in the header is shown. |
| onHeightChange | VoidFunction | () => {} | The callback function triggered when the maximize button is clicked and the height changes. |
| detach | boolean | false | Set to true to detach the bottom sheet from the left side and the bottom and create a little offset. |
| detachOffset | number | 15 | Defines the amount of pixels for the sheet. |
| hasBackdrop | boolean | false | Set to true to render a modal like backdrop to emphasize the bottom sheet. |
| onBackdropClick | VoidFunction | () => {} | Callback function triggered when the backdrop is clicked. Usually used to close the bottom sheet. |
| bodyRef | MutableRefObject<HTMLDivElement \| null> | — | A react ref added to the bottom sheet body. |
| bodyClassName | string | — | Additional classes to be set on the body element. |
| className | string | — | Additional classes to be set on the wrapping element. |

## TimedBottomSheet

### Example: Example 5

Showcase of a timed bottom sheet used for requesting feedback from the user after a major feature was released or updated.
Trigger timed bottom sheet

#### React (tsx)

```tsx
import { useState } from 'react';

import Button from '@rio-cloud/rio-uikit/Button';
import ToggleButton from '@rio-cloud/rio-uikit/ToggleButton';
import SimpleTooltip from '@rio-cloud/rio-uikit/SimpleTooltip';
import TimedBottomSheet from '@rio-cloud/rio-uikit/TimedBottomSheet';
import { motion } from '@rio-cloud/rio-uikit/motion';
import useLocalStorage from '@rio-cloud/rio-uikit/useLocalStorage';

/*
 * Don't forget to cleanup the localStorage for the user when removing a feature
 * by setting "cleanupLocalStorage" to "true" and deploy it like this.
 * The cleanup will remove the localStorage flag on mount and will not show the bottom sheet.
 */

const IS_DISABLED = false;

const SHOW_AFTER_IN_MS = 2_000; // 2 seconds
const HIDE_AFTER_IN_MS = 120_000; // 2 minutes
const HIDE_AFTER_SUBMIT_IN_MS = 2_000;

export const FeedbackBottomSheet = ({ onClose }: { onClose: VoidFunction }) => {
    const [isDismissed, setIsDismissed] = useState(false);
    const [isSubmitted, setIsSubmitted] = useState(false);
    const [isPostponed, setIsPostponed] = useState(false);

    const [rating, setRating] = useState<number>();

    // Don't close itself if the user types in into the textfield or
    // interacts with the bottom sheet
    const [isDirty, setIsDirty] = useState(false);

    const handleCloseBottomSheet = () => {
        setIsDismissed(true);
        onClose();
    };

    const handlePostpone = () => {
        setIsPostponed(true);
        onClose();
    };

    const handleRating = (value: number | undefined) => {
        setIsDirty(true);
        setRating(value);
    };

    const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
        // Avoid page reload on submit
        event.preventDefault();

        // Get form data of all inputs
        const data = new FormData(event.target as HTMLFormElement);
        console.log(Object.fromEntries(data.entries()));

        sendFeedback(data.get('mapFeedbackText')?.toString() || '', rating);

        // show thank you message and close bottom sheet after 5 sec
        setIsSubmitted(true);

        // After showing the thank you message, set the bottom sheet to dismissed, so it won't be
        // shown again on next page load
        setTimeout(() => {
            setIsDismissed(true);
            onClose();
        }, HIDE_AFTER_SUBMIT_IN_MS);
    };

    const sendFeedback = (messageToSend: string, _featureRating: number | undefined) => {
        console.log(`Sending email with message \n${messageToSend}`);
    };

    let hideTimeout: number | undefined = isSubmitted ? HIDE_AFTER_SUBMIT_IN_MS : HIDE_AFTER_IN_MS;
    if (isDirty) {
        hideTimeout = undefined;
    }

    if (isPostponed) {
        return null;
    }

    return (
        <TimedBottomSheet
            featureName='mapUpdateFeedbackBottomSheet'
            localStoragePrefix='uikit.'
            dismissed={isDismissed}
            showAfter={SHOW_AFTER_IN_MS}
            hideAfter={hideTimeout}
            onClose={handleCloseBottomSheet}
            bodyClassName='padding-25'
            className='width-400'
            cleanupLocalStorage={IS_DISABLED}
        >
            {!isSubmitted && !isPostponed && (
                <form onSubmit={handleSubmit}>
                    <div className='text-size-18 text-medium'>Map update feedback</div>
                    <p className='margin-top-5 margin-bottom-25 text-color-darker'>
                        Please take a moment to tell us what you think of the new map update. Haven't noticed a change?{' '}
                        <a href='#'>Read here what's new...</a>
                    </p>
                    <div className='text-color-darker text-medium'>Rate your experience with the map</div>
                    <div className='btn-toolbar text-size-14 align-items-center margin-top-5 margin-bottom-25'>
                        <div className='text-size-200pct text-color-danger rioglyph rioglyph-thumbs-down' />
                        <ToggleButton
                            active={rating === 1}
                            onClick={(toggled: boolean) => handleRating(toggled ? 1 : undefined)}
                        >
                            1
                        </ToggleButton>
                        <ToggleButton
                            active={rating === 2}
                            onClick={(toggled: boolean) => handleRating(toggled ? 2 : undefined)}
                        >
                            2
                        </ToggleButton>
                        <ToggleButton
                            active={rating === 3}
                            onClick={(toggled: boolean) => handleRating(toggled ? 3 : undefined)}
                        >
                            3
                        </ToggleButton>
                        <ToggleButton
                            active={rating === 4}
                            onClick={(toggled: boolean) => handleRating(toggled ? 4 : undefined)}
                        >
                            4
                        </ToggleButton>
                        <ToggleButton
                            active={rating === 5}
                            onClick={(toggled: boolean) => handleRating(toggled ? 5 : undefined)}
                        >
                            5
                        </ToggleButton>
                        <div className='text-size-200pct text-color-success rioglyph rioglyph-thumbs-up' />
                    </div>
                    <div className='margin-bottom-15'>
                        <div className='text-color-darker text-medium margin-bottom-5 margin-right-20'>
                            Anything that can be improved or something you want to tell us
                        </div>
                        <textarea
                            name='mapFeedbackText'
                            className='form-control'
                            cols={3}
                            placeholder='Your feedback (optional)'
                            onClick={() => setIsDirty(true)}
                        />
                    </div>
                    <div className='btn-toolbar display-flex justify-content-end align-items-center margin-top-15'>
                        <Button
                            bsStyle='muted'
                            className='hover-bg-lightest text-color-dark hover-text-color-darker'
                            onClick={handlePostpone}
                        >
                            Ask me later
                        </Button>
                        {rating === undefined ? (
                            <SimpleTooltip content='Please give a rating' placement='top'>
                                <div>
                                    <Button bsStyle='primary' type='submit' disabled>
                                        Send feedback
                                    </Button>
                                </div>
                            </SimpleTooltip>
                        ) : (
                            <Button bsStyle='primary' type='submit'>
                                Send feedback
                            </Button>
                        )}
                    </div>
                </form>
            )}
            {isSubmitted && (
                <motion.div
                    initial={{ opacity: 0, x: 20 }}
                    animate={{ opacity: 1, x: 0 }}
                    className='display-flex gap-10 align-items-center'
                >
                    <div className='text-color-success text-size-20'>
                        <span className='rioglyph rioglyph-ok-sign' />
                    </div>
                    <div className='text-medium text-color-darker text-size-16'>Thank you for your feedback</div>
                </motion.div>
            )}
        </TimedBottomSheet>
    );
};

export default () => {
    const [showFeedback, setShowFeedback] = useState(false);

    // For demo purpose, we have to cleanup the local storage to show the bottom sheet again
    const [, , removeFlag] = useLocalStorage('uikit.hideMapUpdateFeedbackBottomSheet', false);

    const handleShowFeedback = () => {
        removeFlag();

        setTimeout(() => {
            setShowFeedback(true);
        });
    };

    const handleCloseFeedback = () => {
        removeFlag();
        setShowFeedback(false);
    };

    return (
        <>
            <p>
                Showcase of a timed bottom sheet used for requesting feedback from the user after a major feature was
                released or updated.
            </p>
            <Button bsStyle='primary' onClick={handleShowFeedback}>
                Trigger timed bottom sheet
            </Button>
            {showFeedback && <FeedbackBottomSheet onClose={handleCloseFeedback} />}
        </>
    );
};
```

#### HTML (html)

```html
<p>Showcase of a timed bottom sheet used for requesting feedback from the user after a major feature was released or updated.</p>
<button type="button" class="btn btn-primary btn-component" tabindex="0">Trigger timed bottom sheet</button>
```

#### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| dismissed | boolean | false | The dismissed flag can be used to tell this component that the user has clicked on the content of the component like a button or a link. In this case, the bottom sheet will store a flag in the localStorage to hide the bottom sheet for the next time and it will close the sheet right away. |
| featureName | string | — | The featureName prop is used to name the localStorage flag that is used to control the visibility. It should be unique to avoid conflicts with other timed bottom sheets. |
| showAfter | number | 0 | Defines the time in milliseconds when the bottom sheet shall be shown. Default value is 0 to show it right away. |
| hideAfter | number | 3_600_000 | Defines the time in milliseconds when the bottom sheet hides itself automatically. Default value is 3_600_000 to hide it after 1 hour. In this case, the localStorage flag is not set and the bottom sheet will be shown on the next page load. |
| alwaysOn | boolean | false | With this enabled, the BottomSheet will not hide automatically. |
| showCloseButton | boolean | true | Enables or disabled the close button. |
| width | number | — | Optional width of the bottom sheet. Alternatively, you can set a max-width-xxx via className instead. |
| cleanupLocalStorage | boolean | false | Flag to allow to remove the localStorage flag again once the component is not needed anymore. |
| localStoragePrefix | string | — | A prefix that will be used for the local storage flag to store whether the bottom sheet should be hidden. Use this prefix for your service name for instance. |
| onClose | () => void | () => {} | Callback function that gets triggered when the user closed the bottom sheet with the close button. |
| bodyClassName | string | 'padding-25 margin-right-25' | Optional className to be set on the body. |
| className | string | — | Optional className to be set on the component. Use this to define a max-width value. |