Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion articles/components/scroller/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ page-links:
Scroller is a container component that enables scrollable areas within the UI.
// end::description[]

[.example]
[.example,themes="lumo,aura"]
--

ifdef::lit[]
Expand Down
92 changes: 43 additions & 49 deletions frontend/demo/component/scroller/react/scroller-basic.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,56 @@
import '@vaadin/icons';
import { reactExample } from 'Frontend/demo/react-example'; // hidden-source-line
import React from 'react';
import { Button } from '@vaadin/react-components/Button.js';
import { DatePicker } from '@vaadin/react-components/DatePicker.js';
import { Icon } from '@vaadin/react-components/Icon.js';
import { Card } from '@vaadin/react-components/Card.js';
import { Markdown } from '@vaadin/react-components/Markdown.js';
import { Scroller } from '@vaadin/react-components/Scroller.js';
import { TextArea } from '@vaadin/react-components/TextArea.js';
import { TextField } from '@vaadin/react-components/TextField.js';
import { VerticalLayout } from '@vaadin/react-components/VerticalLayout.js';
import exampleStyles from './scroller-basic-styles'; // hidden-source-line

const headerStyle = {
display: 'flex',
alignItems: 'center',
gap: '1rem',
padding: '1rem',
borderBottom: 'solid 1px var(--vaadin-border-color)',
};

const eventDetails = `
**Date & Time**

Saturday, July 19, 2025
9:00 AM – 5:00 PM (PDT)

**About This Event**

Join us for a full day of inspiring talks, hands-on workshops, and networking opportunities with industry leaders. Whether you're a seasoned developer or just starting out, there's something for everyone.

**Schedule**

- **9:00 AM** – Registration & Breakfast
- **10:00 AM** – Opening Keynote
- **11:30 AM** – Breakout Sessions
- **1:00 PM** – Lunch & Networking
- **2:30 PM** – Afternoon Workshops
- **4:30 PM** – Closing Remarks & Raffle

**What to Bring**

- Photo ID for check-in
- Laptop (optional, for workshops)
- Business cards for networking

**Parking**

Free parking available in Lot B. Street parking is limited.

**Contact**

Questions? Email us at [email protected]
`;

function Example() {
return (
<VerticalLayout id="container">
<header style={headerStyle}>
<a href="#" aria-label="Go back">
<Icon icon="vaadin:arrow-left" style={{ padding: '0.25rem' }} aria-hidden="true" />
</a>
<h2 style={{ fontSize: '1.375rem' }}>Edit employee</h2>
</header>

<Card style={{ maxWidth: '400px' }}>
<div slot="title">Summer Tech Conference 2025</div>
{/* tag::snippet[] */}
<Scroller
style={{ borderBottom: 'solid 1px var(--vaadin-border-color)', padding: '1rem' }}
scrollDirection="vertical"
>
<section aria-labelledby="personal-title">
<h3 id="personal-title" style={{ fontSize: '1.125rem' }}>
Personal information
</h3>
<TextField style={{ width: '100%' }} label="First name" />
<TextField style={{ width: '100%' }} label="Last name" />
<DatePicker initialPosition="1990-01-01" label="Birthdate" style={{ width: '100%' }} />
</section>
<section aria-labelledby="employment-title">
<h3 id="employment-title" style={{ fontSize: '1.125rem', marginTop: '1.5rem' }}>
Employment information
</h3>
<TextField style={{ width: '100%' }} label="Position" />
<TextArea style={{ width: '100%' }} label="Additional information" />
</section>
<Scroller theme="overflow-indicators" style={{ maxHeight: '300px' }}>
<Markdown>{eventDetails}</Markdown>
</Scroller>
{/* end::snippet[] */}

<footer style={{ display: 'flex', gap: '0.5rem', padding: '0.5rem 1rem' }}>
<Button theme="primary">Save</Button>
<Button theme="tertiary">Reset</Button>
</footer>
</VerticalLayout>
<Button slot="footer">Add to calendar</Button>
</Card>
);
}

export default reactExample(Example, exampleStyles); // hidden-source-line
export default reactExample(Example); // hidden-source-line
103 changes: 41 additions & 62 deletions frontend/demo/component/scroller/scroller-basic.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
import 'Frontend/demo/init'; // hidden-source-line
import '@vaadin/button';
import '@vaadin/date-picker';
import '@vaadin/icon';
import '@vaadin/icons';
import '@vaadin/card';
import '@vaadin/scroller';
import '@vaadin/text-area';
import '@vaadin/text-field';
import '@vaadin/vertical-layout';
import { css, html, LitElement } from 'lit';
import '@vaadin/markdown';
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
import { applyTheme } from 'Frontend/demo/theme';

@customElement('scroller-basic')
export class Example extends LitElement {
static override styles = css`
#container {
align-items: stretch;
border: 1px solid var(--vaadin-border-color);
max-width: 100%;
height: 400px;
width: 360px;
}
private eventDetails = `
**Date & Time**

header {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
border-bottom: solid 1px var(--vaadin-border-color);
}
`;
Saturday, July 19, 2025
9:00 AM – 5:00 PM (PDT)

**About This Event**

Join us for a full day of inspiring talks, hands-on workshops, and networking opportunities with industry leaders. Whether you're a seasoned developer or just starting out, there's something for everyone.

**Schedule**

- **9:00 AM** – Registration & Breakfast
- **10:00 AM** – Opening Keynote
- **11:30 AM** – Breakout Sessions
- **1:00 PM** – Lunch & Networking
- **2:30 PM** – Afternoon Workshops
- **4:30 PM** – Closing Remarks & Raffle

**What to Bring**

- Photo ID for check-in
- Laptop (optional, for workshops)
- Business cards for networking

**Parking**

Free parking available in Lot B. Street parking is limited.

**Contact**

Questions? Email us at [email protected]
`;

protected override createRenderRoot() {
const root = super.createRenderRoot();
Expand All @@ -39,48 +51,15 @@ export class Example extends LitElement {

protected override render() {
return html`
<vaadin-vertical-layout id="container">
<header>
<a href="#" aria-label="Go back">
<vaadin-icon
icon="vaadin:arrow-left"
style="padding: 0.25rem"
aria-hidden="true"
></vaadin-icon>
</a>
<h2 style="font-size: 1.375rem">Edit employee</h2>
</header>

<vaadin-card style="max-width: 400px">
<div slot="title">Summer Tech Conference 2025</div>
<!-- tag::snippet[] -->
<vaadin-scroller
style="border-bottom: solid 1px var(--vaadin-border-color); padding: 1rem"
scroll-direction="vertical"
>
<section aria-labelledby="personal-title">
<h3 id="personal-title" style="font-size: 1.125rem">Personal information</h3>
<vaadin-text-field style="width: 100%" label="First name"></vaadin-text-field>
<vaadin-text-field style="width: 100%" label="Last name"></vaadin-text-field>
<vaadin-date-picker
style="width: 100%"
initial-position="1990-01-01"
label="Birthdate"
></vaadin-date-picker>
</section>
<section aria-labelledby="employment-title">
<h3 id="employment-title" style="font-size: 1.125rem; margin-top: 1.5rem">
Employment information
</h3>
<vaadin-text-field style="width: 100%" label="Position"></vaadin-text-field>
<vaadin-text-area style="width: 100%" label="Additional information"></vaadin-text-area>
</section>
<vaadin-scroller theme="overflow-indicators" style="max-height: 300px">
<vaadin-markdown .content="${this.eventDetails}"></vaadin-markdown>
</vaadin-scroller>
<!-- end::snippet[] -->

<footer style="display: flex; gap: 0.5rem; padding: 0.5rem 1rem">
<vaadin-button theme="primary">Save</vaadin-button>
<vaadin-button theme="tertiary">Reset</vaadin-button>
</footer>
</vaadin-vertical-layout>
<vaadin-button slot="footer">Add to calendar</vaadin-button>
</vaadin-card>
`;
}
}
135 changes: 46 additions & 89 deletions src/main/java/com/vaadin/demo/component/scroller/ScrollerBasic.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,111 +3,68 @@
import com.vaadin.demo.DemoExporter; // hidden-source-line
import com.vaadin.flow.component.Unit;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.html.*;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.card.Card;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.markdown.Markdown;
import com.vaadin.flow.component.orderedlayout.Scroller;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;

import java.time.LocalDate;

@Route("scroller-basic")
public class ScrollerBasic extends VerticalLayout {
public class ScrollerBasic extends Div {

public static final String PERSONAL_TITLE_ID = "personal-title";
public static final String EMPLOYMENT_TITLE_ID = "employment-title";
private static final String EVENT_DETAILS = """
**Date & Time**

public ScrollerBasic() {
getStyle().set("border", "solid 1px var(--vaadin-border-color)");
setHeight(400, Unit.PIXELS);
setMaxWidth(100, Unit.PERCENTAGE);
setPadding(false);
setSpacing(false);
setWidth(360, Unit.PIXELS);
setAlignItems(FlexComponent.Alignment.STRETCH);
Saturday, July 19, 2025
9:00 AM – 5:00 PM (PDT)

**About This Event**

Join us for a full day of inspiring talks, hands-on workshops, and networking opportunities with industry leaders. Whether you're a seasoned developer or just starting out, there's something for everyone.

**Schedule**

- **9:00 AM** – Registration & Breakfast
- **10:00 AM** – Opening Keynote
- **11:30 AM** – Breakout Sessions
- **1:00 PM** – Lunch & Networking
- **2:30 PM** – Afternoon Workshops
- **4:30 PM** – Closing Remarks & Raffle

// Header
Header header = new Header();
header.getStyle().set("display", "flex").set("align-items", "center")
.set("gap", "1rem").set("padding", "1rem")
.set("border-bottom", "solid 1px #ccc");
**What to Bring**

H2 editEmployee = new H2("Edit employee");
editEmployee.getStyle().set("font-size", "1.375rem");
- Photo ID for check-in
- Laptop (optional, for workshops)
- Business cards for networking

Icon arrowLeft = VaadinIcon.ARROW_LEFT.create();
arrowLeft.getStyle().set("padding", "0.25rem");
arrowLeft.getElement().setAttribute("aria-hidden", "true");
**Parking**

Anchor goBack = new Anchor("#", arrowLeft);
goBack.setAriaLabel("Go back");
Free parking available in Lot B. Street parking is limited.

header.add(goBack, editEmployee);
add(header);
**Contact**

Questions? Email us at [email protected]
""";

public ScrollerBasic() {
Card card = new Card();
card.setMaxWidth(400, Unit.PIXELS);

card.setTitle("Summer Tech Conference 2025");

// tag::snippet[]
// Personal information
H3 personalTitle = new H3("Personal information");
personalTitle.getStyle().set("font-size", "1.125rem");
personalTitle.setId(PERSONAL_TITLE_ID);

TextField firstName = new TextField("First name");
firstName.setWidthFull();

TextField lastName = new TextField("Last name");
lastName.setWidthFull();

DatePicker birthDate = new DatePicker("Birthdate");
birthDate.setInitialPosition(LocalDate.of(1990, 1, 1));
birthDate.setWidthFull();

Section personalInformation = new Section(personalTitle, firstName,
lastName, birthDate);
personalInformation.getElement().setAttribute("aria-labelledby",
PERSONAL_TITLE_ID);

// Employment information
H3 employmentTitle = new H3("Employment information");
employmentTitle.getStyle().set("font-size", "1.125rem")
.set("margin-top", "1.5rem");
employmentTitle.setId(EMPLOYMENT_TITLE_ID);

TextField position = new TextField("Position");
position.setWidthFull();

TextArea additionalInformation = new TextArea("Additional Information");
additionalInformation.setWidthFull();

Section employmentInformation = new Section(employmentTitle, position,
additionalInformation);
employmentInformation.getElement().setAttribute("aria-labelledby",
EMPLOYMENT_TITLE_ID);

Scroller scroller = new Scroller(
new Div(personalInformation, employmentInformation));
scroller.getStyle().set("border-bottom", "solid 1px #ccc")
.set("padding", "1rem");
scroller.setScrollDirection(Scroller.ScrollDirection.VERTICAL);
add(scroller);
// end::snippet[]
Markdown markdown = new Markdown(EVENT_DETAILS);

// Footer
Button save = new Button("Save");
save.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
Scroller scroller = new Scroller(markdown);
scroller.addThemeName("overflow-indicators");
scroller.setMaxHeight(300, Unit.PIXELS);
// end::snippet[]
card.add(scroller);

Button reset = new Button("Reset");
reset.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
Button addToCalendar = new Button("Add to calendar");
card.addToFooter(addToCalendar);

Footer footer = new Footer(save, reset);
footer.getStyle().set("display", "flex").set("gap", "0.5rem")
.set("padding", "0.5rem 1rem");
add(footer);
add(card);
}

public static class Exporter extends DemoExporter<ScrollerBasic> { // hidden-source-line
Expand Down