<commit_before># Popup

[component-header:sl-popup]

Popup is a utility that lets you declaratively anchor "popup" containers to another element.

This component's name is inspired by [`<popup>`](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md). It uses [Floating UI](https://floating-ui.com/) under the hood to provide a well-tested, lightweight, and fully declarative positioning utility for tooltips, dropdowns, and more.

Popup doesn't provide any styles — just positioning! The popup's preferred placement, distance, and skidding (offset) can be configured using attributes. An arrow that points to the anchor can be shown and customized to your liking. Additional positioning options are available and described in more detail below.

```html preview
<div class="popup-overview">
  <sl-popup placement="top" active>
    <span slot="anchor"></span>
    <div class="box"></div>
  </sl-popup>

  <div class="popup-overview-options">
    <sl-select label="Placement" name="placement" value="top" class="popup-overview-select">
      <sl-menu-item value="top">top</sl-menu-item>
      <sl-menu-item value="top-start">top-start</sl-menu-item>
      <sl-menu-item value="top-end">top-end</sl-menu-item>
      <sl-menu-item value="bottom">bottom</sl-menu-item>
      <sl-menu-item value="bottom-start">bottom-start</sl-menu-item>
      <sl-menu-item value="bottom-end">bottom-end</sl-menu-item>
      <sl-menu-item value="right">right</sl-menu-item>
      <sl-menu-item value="right-start">right-start</sl-menu-item>
      <sl-menu-item value="right-end">right-end</sl-menu-item>
      <sl-menu-item value="left">left</sl-menu-item>
      <sl-menu-item value="left-start">left-start</sl-menu-item>
      <sl-menu-item value="left-end">left-end</sl-menu-item>
    </sl-select>
    <sl-input type="number" name="distance" label="distance" value="0"></sl-input>
    <sl-input type="number" name="skidding" label="Skidding" value="0"></sl-input>
  </div>

  <div class="popup-overview-options">
    <sl-switch name="active" checked>Active</sl-switch>
    <sl-switch name="arrow">Arrow</sl-switch>
  </div>
</div>

<script>
  const container = document.querySelector('.popup-overview');
  const popup = container.querySelector('sl-popup');
  const select = container.querySelector('sl-select[name="placement"]');
  const distance = container.querySelector('sl-input[name="distance"]');
  const skidding = container.querySelector('sl-input[name="skidding"]');
  const active = container.querySelector('sl-switch[name="active"]');
  const arrow = container.querySelector('sl-switch[name="arrow"]');

  select.addEventListener('sl-change', () => (popup.placement = select.value));
  distance.addEventListener('sl-input', () => (popup.distance = distance.value));
  skidding.addEventListener('sl-input', () => (popup.skidding = skidding.value));
  active.addEventListener('sl-change', () => (popup.active = active.checked));
  arrow.addEventListener('sl-change', () => (popup.arrow = arrow.checked));
</script>

<style>
  .popup-overview sl-popup {
    --arrow-color: var(--sl-color-primary-600);
  }

  .popup-overview span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--sl-color-neutral-600);
    margin: 50px;
  }

  .popup-overview .box {
    width: 100px;
    height: 50px;
    background: var(--sl-color-primary-600);
    border-radius: var(--sl-border-radius-medium);
  }

  .popup-overview-options {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 1rem;
  }

  .popup-overview-options sl-select {
    width: 160px;
  }

  .popup-overview-options sl-input {
    width: 100px;
  }

  .popup-overview-options + .popup-overview-options {
    margin-top: 1rem;
  }
</style>
```

```jsx react
import { useState } from 'react';
import { SlPopup, SlSelect, SlMenuItem, SlInput, SlSwitch } from '@shoelace-style/shoelace/dist/react';

const css = `
  .popup-overview sl-popup {
    --arrow-color: var(--sl-color-primary-600);
  }

  .popup-overview span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--sl-color-neutral-600);
    margin: 50px;
  }

  .popup-overview .box {
    width: 100px;
    height: 50px;
    background: var(--sl-color-primary-600);
    border-radius: var(--sl-border-radius-medium);
  }

  .popup-overview-options {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 1rem;
  }

  .popup-overview-options sl-select {
    width: 160px;
  }

  .popup-overview-options sl-input {
    width: 100px;
  }

  .popup-overview-options + .popup-overview-options {
    margin-top: 1rem;
  }
`;

const App = () => {
  const [placement, setPlacement] = useState('top');
  const [distance, setDistance] = useState(0);
  const [skidding, setSkidding] = useState(0);
  const [active, setActive] = useState(true);
  const [arrow, setArrow] = useState(false);

  return (
    <>
      <div className="popup-overview">
        <SlPopup
          placement={placement}
          active={active || null}
          distance={distance}
          skidding={skidding}
          arrow={arrow || null}
        >
          <span slot="anchor" />
          <div className="box" />
        </SlPopup>

        <div className="popup-overview-options">
          <SlSelect
            label="Placement"
            name="placement"
            value={placement}
            className="popup-overview-select"
            onSlChange={event => setPlacement(event.target.value)}
          >
            <SlMenuItem value="top">top</SlMenuItem>
            <SlMenuItem value="top-start">top-start</SlMenuItem>
            <SlMenuItem value="top-end">top-end</SlMenuItem>
            <SlMenuItem value="bottom">bottom</SlMenuItem>
            <SlMenuItem value="bottom-start">bottom-start</SlMenuItem>
            <SlMenuItem value="bottom-end">bottom-end</SlMenuItem>
            <SlMenuItem value="right">right</SlMenuItem>
            <SlMenuItem value="right-start">right-start</SlMenuItem>
            <SlMenuItem value="right-end">right-end</SlMenuItem>
            <SlMenuItem value="left">left</SlMenuItem>
            <SlMenuItem value="left-start">left-start</SlMenuItem>
            <SlMenuItem value="left-end">left-end</SlMenuItem>
          </SlSelect>
          <SlInput
            type="number"
            name="distance"
            label="distance"
            value={distance}
            onSlInput={event => setDistance(event.target.value)}
          />
          <SlInput
            type="number"
            name="skidding"
            label="Skidding"
            value={distance}<commit_msg>fix example<commit_after># Popup

[component-header:sl-popup]

Popup is a utility that lets you declaratively anchor "popup" containers to another element.

This component's name is inspired by [`<popup>`](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md). It uses [Floating UI](https://floating-ui.com/) under the hood to provide a well-tested, lightweight, and fully declarative positioning utility for tooltips, dropdowns, and more.

Popup doesn't provide any styles — just positioning! The popup's preferred placement, distance, and skidding (offset) can be configured using attributes. An arrow that points to the anchor can be shown and customized to your liking. Additional positioning options are available and described in more detail below.

```html preview
<div class="popup-overview">
  <sl-popup placement="top" active>
    <span slot="anchor"></span>
    <div class="box"></div>
  </sl-popup>

  <div class="popup-overview-options">
    <sl-select label="Placement" name="placement" value="top" class="popup-overview-select">
      <sl-menu-item value="top">top</sl-menu-item>
      <sl-menu-item value="top-start">top-start</sl-menu-item>
      <sl-menu-item value="top-end">top-end</sl-menu-item>
      <sl-menu-item value="bottom">bottom</sl-menu-item>
      <sl-menu-item value="bottom-start">bottom-start</sl-menu-item>
      <sl-menu-item value="bottom-end">bottom-end</sl-menu-item>
      <sl-menu-item value="right">right</sl-menu-item>
      <sl-menu-item value="right-start">right-start</sl-menu-item>
      <sl-menu-item value="right-end">right-end</sl-menu-item>
      <sl-menu-item value="left">left</sl-menu-item>
      <sl-menu-item value="left-start">left-start</sl-menu-item>
      <sl-menu-item value="left-end">left-end</sl-menu-item>
    </sl-select>
    <sl-input type="number" name="distance" label="distance" value="0"></sl-input>
    <sl-input type="number" name="skidding" label="Skidding" value="0"></sl-input>
  </div>

  <div class="popup-overview-options">
    <sl-switch name="active" checked>Active</sl-switch>
    <sl-switch name="arrow">Arrow</sl-switch>
  </div>
</div>

<script>
  const container = document.querySelector('.popup-overview');
  const popup = container.querySelector('sl-popup');
  const select = container.querySelector('sl-select[name="placement"]');
  const distance = container.querySelector('sl-input[name="distance"]');
  const skidding = container.querySelector('sl-input[name="skidding"]');
  const active = container.querySelector('sl-switch[name="active"]');
  const arrow = container.querySelector('sl-switch[name="arrow"]');

  select.addEventListener('sl-change', () => (popup.placement = select.value));
  distance.addEventListener('sl-input', () => (popup.distance = distance.value));
  skidding.addEventListener('sl-input', () => (popup.skidding = skidding.value));
  active.addEventListener('sl-change', () => (popup.active = active.checked));
  arrow.addEventListener('sl-change', () => (popup.arrow = arrow.checked));
</script>

<style>
  .popup-overview sl-popup {
    --arrow-color: var(--sl-color-primary-600);
  }

  .popup-overview span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--sl-color-neutral-600);
    margin: 50px;
  }

  .popup-overview .box {
    width: 100px;
    height: 50px;
    background: var(--sl-color-primary-600);
    border-radius: var(--sl-border-radius-medium);
  }

  .popup-overview-options {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 1rem;
  }

  .popup-overview-options sl-select {
    width: 160px;
  }

  .popup-overview-options sl-input {
    width: 100px;
  }

  .popup-overview-options + .popup-overview-options {
    margin-top: 1rem;
  }
</style>
```

```jsx react
import { useState } from 'react';
import { SlPopup, SlSelect, SlMenuItem, SlInput, SlSwitch } from '@shoelace-style/shoelace/dist/react';

const css = `
  .popup-overview sl-popup {
    --arrow-color: var(--sl-color-primary-600);
  }

  .popup-overview span[slot='anchor'] {
    display: inline-block;
    width: 150px;
    height: 150px;
    border: dashed 2px var(--sl-color-neutral-600);
    margin: 50px;
  }

  .popup-overview .box {
    width: 100px;
    height: 50px;
    background: var(--sl-color-primary-600);
    border-radius: var(--sl-border-radius-medium);
  }

  .popup-overview-options {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 1rem;
  }

  .popup-overview-options sl-select {
    width: 160px;
  }

  .popup-overview-options sl-input {
    width: 100px;
  }

  .popup-overview-options + .popup-overview-options {
    margin-top: 1rem;
  }
`;

const App = () => {
  const [placement, setPlacement] = useState('top');
  const [distance, setDistance] = useState(0);
  const [skidding, setSkidding] = useState(0);
  const [active, setActive] = useState(true);
  const [arrow, setArrow] = useState(false);

  return (
    <>
      <div className="popup-overview">
        <SlPopup
          placement={placement}
          active={active || null}
          distance={distance}
          skidding={skidding}
          arrow={arrow || null}
        >
          <span slot="anchor" />
          <div className="box" />
        </SlPopup>

        <div className="popup-overview-options">
          <SlSelect
            label="Placement"
            name="placement"
            value={placement}
            className="popup-overview-select"
            onSlChange={event => setPlacement(event.target.value)}
          >
            <SlMenuItem value="top">top</SlMenuItem>
            <SlMenuItem value="top-start">top-start</SlMenuItem>
            <SlMenuItem value="top-end">top-end</SlMenuItem>
            <SlMenuItem value="bottom">bottom</SlMenuItem>
            <SlMenuItem value="bottom-start">bottom-start</SlMenuItem>
            <SlMenuItem value="bottom-end">bottom-end</SlMenuItem>
            <SlMenuItem value="right">right</SlMenuItem>
            <SlMenuItem value="right-start">right-start</SlMenuItem>
            <SlMenuItem value="right-end">right-end</SlMenuItem>
            <SlMenuItem value="left">left</SlMenuItem>
            <SlMenuItem value="left-start">left-start</SlMenuItem>
            <SlMenuItem value="left-end">left-end</SlMenuItem>
          </SlSelect>
          <SlInput
            type="number"
            name="distance"
            label="distance"
            value={distance}
            onSlInput={event => setDistance(event.target.value)}
          />
          <SlInput
            type="number"
            name="skidding"
            label="Skidding"
            value={skidding}
{'fraction_non_alphanumeric': 0.15926424405563033, 'fraction_numerical': 0.00986989681471512, 'mean_word_length': 3.0554881746513036, 'pattern_counts': {'":': 0, '<': 175, '<?xml version=': 0, '>': 189, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3273497', 'n_tokens_mistral': 4299, 'n_tokens_neox': 4103, 'n_words': 790}