or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions-buttons.mdcore-application.mddata-display.mdfeedback-overlays.mdform-components.mdindex.mdlayout-utilities.mdmedia-icons.mdnavigation.mdtypes-interfaces.mdutilities-hooks.md

feedback-overlays.mddocs/

0

# Feedback & Overlay Components

1

2

Modal dialogs, notifications, tooltips, and overlay components for providing user feedback, contextual information, and interactive experiences. These components handle focus management, accessibility, and proper layering.

3

4

## Capabilities

5

6

### Modal

7

8

Modal dialog component for displaying content in an overlay with backdrop, focus trapping, and accessibility features.

9

10

```typescript { .api }

11

/**

12

* Modal dialog overlay with backdrop and focus management

13

* @param open - Modal visibility state

14

* @param onClose - Modal close handler

15

* @param title - Modal title text

16

* @param children - Modal content

17

* @returns JSX element with modal dialog

18

*/

19

function Modal(props: ModalProps): JSX.Element;

20

21

interface ModalProps extends FooterProps {

22

/** Whether the modal is open or not */

23

open: boolean;

24

/** The url that will be loaded as the content of the modal */

25

src?: string;

26

/** The name of the modal content iframe */

27

iFrameName?: string;

28

/** The content for the title of the modal */

29

title: string | React.ReactNode;

30

/** Hide the title in the modal */

31

titleHidden?: boolean;

32

/** The content to display inside modal */

33

children?: React.ReactNode;

34

/** Inner content of the footer */

35

footer?: React.ReactNode;

36

/** Disable animations and open modal instantly */

37

instant?: boolean;

38

/** Automatically adds sections to modal */

39

sectioned?: boolean;

40

/** The size of the modal */

41

size?: ModalSize;

42

/** Limits modal height on large screens with scrolling */

43

limitHeight?: boolean;

44

/** Replaces modal content with a spinner while a background action is being performed */

45

loading?: boolean;

46

/** Callback when the modal is closed */

47

onClose(): void;

48

/** Callback when iframe has loaded */

49

onIFrameLoad?(evt: React.SyntheticEvent<HTMLIFrameElement>): void;

50

/** Callback when modal transition animation has ended */

51

onTransitionEnd?(): void;

52

/** Callback when the bottom of the modal content is reached */

53

onScrolledToBottom?(): void;

54

/** The element or the RefObject that activates the Modal */

55

activator?: React.RefObject<HTMLElement> | React.ReactElement;

56

/** The element type to wrap the activator in */

57

activatorWrapper?: Element;

58

/** Removes Scrollable container from the modal content */

59

noScroll?: boolean;

60

}

61

62

type ModalSize = 'small' | 'large' | 'fullScreen';

63

64

interface FooterProps {

65

primaryAction?: PrimaryAction;

66

secondaryActions?: SecondaryAction[];

67

}

68

69

interface PrimaryAction {

70

/** Action content */

71

content: string;

72

/** Action callback */

73

onAction: () => void;

74

/** Loading state */

75

loading?: boolean;

76

/** Disabled state */

77

disabled?: boolean;

78

/** Destructive styling */

79

destructive?: boolean;

80

}

81

82

interface SecondaryAction {

83

/** Action content */

84

content: string;

85

/** Action callback */

86

onAction: () => void;

87

/** Loading state */

88

loading?: boolean;

89

/** Disabled state */

90

disabled?: boolean;

91

/** Destructive styling */

92

destructive?: boolean;

93

/** Help text */

94

helpText?: string;

95

/** Accessibility label */

96

accessibilityLabel?: string;

97

/** Icon */

98

icon?: IconSource;

99

}

100

```

101

102

**Usage Example:**

103

104

```typescript

105

import React, { useState } from 'react';

106

import { Modal, Button, TextContainer, Text } from '@shopify/polaris';

107

108

function DeleteProductModal() {

109

const [active, setActive] = useState(false);

110

111

const handleClose = () => setActive(false);

112

const handleOpen = () => setActive(true);

113

114

const primaryAction = {

115

content: 'Delete product',

116

destructive: true,

117

onAction: () => {

118

// Handle delete

119

handleClose();

120

},

121

};

122

123

const secondaryActions = [

124

{

125

content: 'Cancel',

126

onAction: handleClose,

127

},

128

];

129

130

return (

131

<>

132

<Button destructive onClick={handleOpen}>

133

Delete Product

134

</Button>

135

<Modal

136

open={active}

137

onClose={handleClose}

138

title="Delete Product"

139

primaryAction={primaryAction}

140

secondaryActions={secondaryActions}

141

>

142

<Modal.Section>

143

<TextContainer>

144

<Text variant="bodyMd">

145

Are you sure you want to delete this product? This action cannot be undone.

146

</Text>

147

</TextContainer>

148

</Modal.Section>

149

</Modal>

150

</>

151

);

152

}

153

```

154

155

### Banner

156

157

Important messaging banner component for displaying alerts, notifications, and status information with various tones.

158

159

```typescript { .api }

160

/**

161

* Important messaging banner with tone and actions

162

* @param title - Banner title

163

* @param children - Banner content

164

* @param tone - Banner tone/color theme

165

* @param onDismiss - Dismiss handler

166

* @returns JSX element with banner

167

*/

168

function Banner(props: BannerProps): JSX.Element;

169

170

interface BannerProps {

171

/** Banner title */

172

title?: string;

173

/** Banner content */

174

children?: React.ReactNode;

175

/** Banner tone */

176

tone?: BannerTone;

177

/** Primary action */

178

action?: Action;

179

/** Secondary action */

180

secondaryAction?: Action;

181

/** Dismiss handler */

182

onDismiss?: () => void;

183

/** Hide icon */

184

hideIcon?: boolean;

185

/** Icon source override */

186

icon?: IconSource;

187

/** Stop announcements */

188

stopAnnouncements?: boolean;

189

}

190

191

/** Banner tone options */

192

enum BannerTone {

193

Info = 'info',

194

Success = 'success',

195

Warning = 'warning',

196

Critical = 'critical',

197

AttentionGrabbing = 'attention-grabbing',

198

}

199

200

interface BannerHandles {

201

/** Focus the banner */

202

focus(): void;

203

}

204

```

205

206

### Toast

207

208

Temporary notification component for brief messages with optional actions and automatic dismissal.

209

210

```typescript { .api }

211

/**

212

* Temporary notification with automatic dismissal

213

* @param content - Toast message content

214

* @param action - Optional action button

215

* @param duration - Display duration in milliseconds

216

* @param onDismiss - Dismiss handler

217

* @returns JSX element with toast notification

218

*/

219

function Toast(props: ToastProps): JSX.Element;

220

221

interface ToastProps {

222

/** Toast message content */

223

content: string;

224

/** Error state */

225

error?: boolean;

226

/** Toast action */

227

action?: Action;

228

/** Display duration */

229

duration?: number;

230

/** Dismiss handler */

231

onDismiss(): void;

232

/** Toast ID */

233

id?: string;

234

}

235

```

236

237

### Popover

238

239

Floating content overlay positioned relative to a trigger element with automatic positioning and interaction handling.

240

241

```typescript { .api }

242

/**

243

* Floating content overlay with positioning

244

* @param activator - Trigger element

245

* @param active - Popover visibility state

246

* @param onClose - Close handler

247

* @param children - Popover content

248

* @returns JSX element with popover overlay

249

*/

250

function Popover(props: PopoverProps): JSX.Element;

251

252

interface PopoverProps {

253

/** Popover visibility */

254

active: boolean;

255

/** Trigger element */

256

activator: React.ReactNode;

257

/** Close handler */

258

onClose: () => void;

259

/** Popover content */

260

children?: React.ReactNode;

261

/** Preferred position */

262

preferredPosition?: 'above' | 'below' | 'mostSpace';

263

/** Preferred alignment */

264

preferredAlignment?: 'left' | 'center' | 'right';

265

/** Full width */

266

fullWidth?: boolean;

267

/** Full height */

268

fullHeight?: boolean;

269

/** Prevent autofocus */

270

preventAutofocus?: boolean;

271

/** Sectioned content */

272

sectioned?: boolean;

273

/** Hide on external click */

274

hideOnPrint?: boolean;

275

/** Popover ID */

276

id?: string;

277

/** Autofocus target */

278

autofocusTarget?: PopoverAutofocusTarget;

279

/** Prevent close on child overlay click */

280

preventCloseOnChildOverlayClick?: boolean;

281

/** Capture overflow */

282

captureOverscroll?: boolean;

283

/** Fixed position */

284

fixed?: boolean;

285

/** Preferred input position */

286

preferInputActivator?: boolean;

287

/** Z-index layer */

288

zIndexOverride?: number;

289

}

290

291

/** Popover autofocus target options */

292

enum PopoverAutofocusTarget {

293

Container = 'container',

294

FirstNode = 'first-node',

295

None = 'none',

296

}

297

298

/** Popover close source tracking */

299

enum PopoverCloseSource {

300

Click = 'click',

301

EscapeKeypress = 'escape-keypress',

302

FocusOut = 'focus-out',

303

ScrollOut = 'scroll-out',

304

}

305

306

interface PopoverPublicAPI {

307

/** Close the popover */

308

close: (source?: PopoverCloseSource) => void;

309

/** Force update position */

310

forceUpdatePosition: () => void;

311

}

312

```

313

314

### Sheet

315

316

Mobile-friendly modal sheet component that slides up from the bottom of the screen.

317

318

```typescript { .api }

319

/**

320

* Mobile-friendly modal sheet sliding from bottom

321

* @param open - Sheet visibility state

322

* @param onClose - Close handler

323

* @param children - Sheet content

324

* @returns JSX element with modal sheet

325

*/

326

function Sheet(props: SheetProps): JSX.Element;

327

328

interface SheetProps {

329

/** Sheet visibility */

330

open: boolean;

331

/** Close handler */

332

onClose: () => void;

333

/** Sheet content */

334

children: React.ReactNode;

335

/** Accessibility label */

336

accessibilityLabel?: string;

337

/** Prevent closing on backdrop click */

338

closing?: boolean;

339

}

340

```

341

342

### Tooltip

343

344

Hover tooltip component providing contextual information and help text for interactive elements.

345

346

```typescript { .api }

347

/**

348

* Hover tooltip for contextual information

349

* @param children - Trigger element

350

* @param content - Tooltip content

351

* @param active - Tooltip visibility override

352

* @returns JSX element with tooltip

353

*/

354

function Tooltip(props: TooltipProps): JSX.Element;

355

356

interface TooltipProps {

357

/** Trigger element */

358

children: React.ReactNode;

359

/** Tooltip content */

360

content: React.ReactNode;

361

/** Manual visibility control */

362

active?: boolean;

363

/** Dismiss callback */

364

onClose?: () => void;

365

/** Preferred position */

366

preferredPosition?: 'above' | 'below' | 'mostSpace';

367

/** Hover delay in milliseconds */

368

hoverDelay?: number;

369

/** Dismissible on outside interaction */

370

dismissOnMouseOut?: boolean;

371

/** Width constraint */

372

width?: 'default' | 'wide';

373

/** Persist on click */

374

persistOnClick?: boolean;

375

/** Z-index override */

376

zIndexOverride?: number;

377

/** Border radius */

378

borderRadius?: BorderRadiusScale;

379

/** Padding override */

380

padding?: SpaceScale;

381

/** Has underline for trigger */

382

hasUnderline?: boolean;

383

/** Accessibility label */

384

accessibilityLabel?: string;

385

}

386

```

387

388

### Backdrop

389

390

Overlay backdrop component for modals and other overlay content with interaction handling.

391

392

```typescript { .api }

393

/**

394

* Overlay backdrop for modals and overlays

395

* @param onClick - Backdrop click handler

396

* @param transparent - Transparent backdrop

397

* @returns JSX element with backdrop overlay

398

*/

399

function Backdrop(props: BackdropProps): JSX.Element;

400

401

interface BackdropProps {

402

/** Backdrop click handler */

403

onClick?: () => void;

404

/** Transparent backdrop */

405

transparent?: boolean;

406

/** Background color override */

407

backgroundColor?: string;

408

/** Z-index override */

409

zIndex?: number;

410

/** Backdrop ID */

411

id?: string;

412

}

413

```

414

415

### Loading

416

417

Global loading indicator component for application-wide loading states.

418

419

```typescript { .api }

420

/**

421

* Global loading indicator

422

* @param loading - Loading state

423

* @returns JSX element with loading indicator

424

*/

425

function Loading(props: LoadingProps): JSX.Element;

426

427

interface LoadingProps {

428

/** Loading state visibility */

429

loading?: boolean;

430

}

431

```

432

433

### Spinner

434

435

Loading spinner component with size options for local loading states.

436

437

```typescript { .api }

438

/**

439

* Loading spinner for local loading states

440

* @param size - Spinner size

441

* @param accessibilityLabel - Accessibility label

442

* @returns JSX element with spinner

443

*/

444

function Spinner(props: SpinnerProps): JSX.Element;

445

446

interface SpinnerProps {

447

/** Spinner size */

448

size?: 'small' | 'large';

449

/** Accessibility label */

450

accessibilityLabel?: string;

451

/** Color override */

452

color?: 'teal' | 'inkLightest';

453

/** Focus management */

454

hasFocusableParent?: boolean;

455

}

456

```

457

458

### ProgressBar

459

460

Progress indicator bar for showing completion status of tasks and processes.

461

462

```typescript { .api }

463

/**

464

* Progress indicator bar

465

* @param progress - Progress percentage (0-100)

466

* @param size - Progress bar size

467

* @returns JSX element with progress bar

468

*/

469

function ProgressBar(props: ProgressBarProps): JSX.Element;

470

471

interface ProgressBarProps {

472

/** Progress percentage (0-100) */

473

progress?: number;

474

/** Progress bar size */

475

size?: 'small' | 'medium' | 'large';

476

/** Color tone */

477

tone?: 'highlight' | 'primary' | 'success' | 'critical';

478

/** Animated progress */

479

animated?: boolean;

480

/** Accessibility label */

481

ariaLabel?: string;

482

}

483

```

484

485

**Usage Example:**

486

487

```typescript

488

import React, { useState } from 'react';

489

import {

490

Banner,

491

Toast,

492

Popover,

493

Button,

494

ActionList,

495

Frame

496

} from '@shopify/polaris';

497

498

function FeedbackExample() {

499

const [toastActive, setToastActive] = useState(false);

500

const [popoverActive, setPopoverActive] = useState(false);

501

502

const toastMarkup = toastActive ? (

503

<Toast

504

content="Product saved successfully"

505

onDismiss={() => setToastActive(false)}

506

/>

507

) : null;

508

509

const activator = (

510

<Button

511

onClick={() => setPopoverActive(!popoverActive)}

512

disclosure

513

>

514

More actions

515

</Button>

516

);

517

518

return (

519

<Frame>

520

<Banner

521

title="Your store is ready to accept payments"

522

tone="success"

523

action={{

524

content: 'Complete setup',

525

onAction: () => console.log('Setup clicked'),

526

}}

527

onDismiss={() => console.log('Banner dismissed')}

528

>

529

<p>Your payment provider has been configured and is ready to process transactions.</p>

530

</Banner>

531

532

<Popover

533

active={popoverActive}

534

activator={activator}

535

onClose={() => setPopoverActive(false)}

536

>

537

<ActionList

538

items={[

539

{

540

content: 'Duplicate',

541

icon: 'duplicate',

542

onAction: () => console.log('Duplicate'),

543

},

544

{

545

content: 'Archive',

546

icon: 'archive',

547

onAction: () => console.log('Archive'),

548

},

549

]}

550

/>

551

</Popover>

552

553

<Button onClick={() => setToastActive(true)}>

554

Show toast

555

</Button>

556

557

{toastMarkup}

558

</Frame>

559

);

560

}

561

```

562

563

## Feedback Constants

564

565

```typescript { .api }

566

/** Default toast display duration in milliseconds */

567

const DEFAULT_TOAST_DURATION: number = 5000;

568

569

/** Default toast duration when action is present in milliseconds */

570

const DEFAULT_TOAST_DURATION_WITH_ACTION: number = 10000;

571

```

572

573

## Shared Feedback Types

574

575

```typescript { .api }

576

/** Icon source type */

577

type IconSource = React.ComponentType<any> | 'placeholder' | string;

578

579

/** Border radius scale for tooltips and overlays */

580

type BorderRadiusScale = '050' | '100' | '150' | '200' | '300' | '400' | '500' | '750';

581

582

/** Space scale for padding and spacing */

583

type SpaceScale =

584

| '025' | '050' | '100' | '150' | '200' | '300' | '400' | '500' | '600'

585

| '800' | '1000' | '1200' | '1600' | '2000' | '2400' | '2800' | '3200';

586

587

/** Action interface for feedback components */

588

interface Action {

589

/** Action content */

590

content?: string;

591

/** Accessibility label */

592

accessibilityLabel?: string;

593

/** Action URL */

594

url?: string;

595

/** External link */

596

external?: boolean;

597

/** Action callback */

598

onAction?(): void;

599

}

600

```

601

602

### Portal

603

604

Low-level component for rendering content outside the normal DOM hierarchy, typically used for overlays and modals.

605

606

```typescript { .api }

607

/**

608

* Renders content outside normal DOM hierarchy

609

* @param children - Content to render in portal

610

* @param idPrefix - Prefix for portal container ID

611

* @param onPortalCreated - Callback when portal is created

612

* @returns JSX element rendered in portal

613

*/

614

function Portal(props: PortalProps): JSX.Element;

615

616

interface PortalProps {

617

/** The content to render inside the portal */

618

children?: React.ReactNode;

619

/** The ID prefix for the portal */

620

idPrefix?: string;

621

/** Callback when the portal is created */

622

onPortalCreated?(): void;

623

}

624

```

625

626

### PortalsManager

627

628

Manager component for coordinating multiple portals and their z-index stacking order.

629

630

```typescript { .api }

631

/**

632

* Manages multiple portals and their stacking order

633

* @param children - Content that may create portals

634

* @returns JSX element with portal management

635

*/

636

function PortalsManager(props: PortalsManagerProps): JSX.Element;

637

638

interface PortalsManagerProps {

639

/** The content to wrap with portal management */

640

children: React.ReactNode;

641

}

642

```

643

644

### PositionedOverlay

645

646

Advanced positioning component for overlays that automatically calculates optimal placement relative to an activator element.

647

648

```typescript { .api }

649

/**

650

* Positions overlay content relative to an activator element

651

* @param active - Whether overlay is visible

652

* @param activator - Element that triggers the overlay

653

* @param children - Overlay content

654

* @param onClose - Close handler

655

* @returns JSX element with positioned overlay

656

*/

657

function PositionedOverlay(props: PositionedOverlayProps): JSX.Element;

658

659

interface PositionedOverlayProps {

660

/** Whether the overlay is active */

661

active: boolean;

662

/** The element that the overlay is positioned relative to */

663

activator: HTMLElement;

664

/** The preferred direction to open */

665

preferredPosition?: 'above' | 'below' | 'mostSpace';

666

/** The preferred alignment of the overlay */

667

preferredAlignment?: 'left' | 'center' | 'right';

668

/** The content of the overlay */

669

children?: React.ReactNode;

670

/** Callback when the overlay should be closed */

671

onClose?(): void;

672

/** Whether to render the overlay with a fixed position */

673

fixed?: boolean;

674

/** The minimum width of the overlay */

675

minWidth?: number;

676

/** Whether to render a full width overlay */

677

fullWidth?: boolean;

678

/** Whether to render the overlay with full height */

679

fullHeight?: boolean;

680

}

681

```

682

683

### ContextualSaveBar

684

685

Save bar that appears when forms have unsaved changes, providing save and discard actions in a prominent banner.

686

687

```typescript { .api }

688

/**

689

* Save bar for forms with unsaved changes

690

* @param message - Message about unsaved changes

691

* @param saveAction - Primary save action

692

* @param discardAction - Discard changes action

693

* @returns JSX element with contextual save bar

694

*/

695

function ContextualSaveBar(props: ContextualSaveBarProps): JSX.Element;

696

697

interface ContextualSaveBarProps {

698

/** Provide a message about the save bar */

699

message?: string;

700

/** Save or commit contextual save bar */

701

saveAction?: ComplexAction;

702

/** Discard or cancel contextual save bar */

703

discardAction?: ComplexAction;

704

/** Remove the normal max-width on the contextual save bar */

705

fullWidth?: boolean;

706

/** Whether the save bar is visible */

707

visible?: boolean;

708

}

709

```

710

711

### Focus

712

713

Focus management component for controlling keyboard navigation and programmatic focus behavior.

714

715

```typescript { .api }

716

/**

717

* Focus management component for keyboard navigation

718

* @param children - Content to manage focus within

719

* @param disabled - Whether focus management is disabled

720

* @returns JSX element with focus management

721

*/

722

function Focus(props: FocusProps): JSX.Element;

723

724

interface FocusProps {

725

/** The content to focus */

726

children?: React.ReactNode;

727

/** Whether the focus is disabled */

728

disabled?: boolean;

729

/** The root element to focus */

730

root?: HTMLElement;

731

}

732

```

733

734

### EventListener

735

736

Component for declaratively adding event listeners with proper cleanup and React lifecycle integration.

737

738

```typescript { .api }

739

/**

740

* Declarative event listener with automatic cleanup

741

* @param event - Event name to listen for

742

* @param handler - Event handler function

743

* @param capture - Use capture phase

744

* @returns JSX element managing event listener

745

*/

746

function EventListener(props: EventListenerProps): JSX.Element;

747

748

interface EventListenerProps {

749

/** The event to listen for */

750

event: string;

751

/** The handler for the event */

752

handler(event: Event): void;

753

/** Whether to capture the event */

754

capture?: boolean;

755

/** Whether the listener is passive */

756

passive?: boolean;

757

/** Whether the listener should be attached once */

758

once?: boolean;

759

}

760

```

761

762

### KeypressListener

763

764

Specialized event listener for keyboard interactions with support for key combinations and modifiers.

765

766

```typescript { .api }

767

/**

768

* Keyboard event listener with key combination support

769

* @param keyCode - Key code to listen for

770

* @param handler - Keypress handler function

771

* @param keyEvent - Type of key event

772

* @returns JSX element managing keypress listener

773

*/

774

function KeypressListener(props: KeypressListenerProps): JSX.Element;

775

776

interface KeypressListenerProps {

777

/** The key code to listen for */

778

keyCode: Key;

779

/** The handler for the keypress */

780

handler(event: KeyboardEvent): void;

781

/** The type of key event to listen for */

782

keyEvent?: 'keydown' | 'keyup';

783

}

784

```

785

786

### ScrollLock

787

788

Component that prevents body scrolling when active, typically used with modals and overlays.

789

790

```typescript { .api }

791

/**

792

* Prevents body scrolling when active

793

* @param children - Content to render while scroll is locked

794

* @returns JSX element with scroll lock behavior

795

*/

796

function ScrollLock(props?: { children?: React.ReactNode }): JSX.Element;

797

```

798

799

### TrapFocus

800

801

Focus trap component that constrains keyboard navigation within its content, essential for modal accessibility.

802

803

```typescript { .api }

804

/**

805

* Constrains keyboard focus within its content

806

* @param children - Content to trap focus within

807

* @param trapping - Whether focus trapping is active

808

* @returns JSX element with focus trapping

809

*/

810

function TrapFocus(props: TrapFocusProps): JSX.Element;

811

812

interface TrapFocusProps {

813

/** Whether to trap focus */

814

trapping?: boolean;

815

/** The content to trap focus within */

816

children?: React.ReactNode;

817

}

818

```