Lang Switcher

@use 'sass:color';
@use 'sprucecss/scss/spruce' as *;

.lang-switcher {
  $this: &;
  min-inline-size: 2.875rem;
  position: relative;
  text-transform: uppercase;

  &--upward {
    #{$this}__panel {
      inset: auto 0 120% auto;
    }

    svg {
      rotate: 180deg;
    }
  }

  &__control {
    @include clear-btn;
    align-items: center;
    border-radius: config('border-radius', $btn);
    color: color('heading');
    display: flex;
    gap: spacer('xxs');
    text-transform: uppercase;

    &:focus-visible {
      @include short-ring('button');
    }
  }

  &__panel {
    @include clear-list;
    background-color: hsl(0deg 0% 0%);
    border-radius: config('border-radius-sm', $display);
    inset: 120% 0 auto auto;
    padding-block: spacer('xxs');
    position: absolute;

    > * + * {
      margin-block-start: 0;
    }

    li {
      line-height: 1;
    }

    a {
      color: hsl(0deg 0% 100%);
      display: flex;
      padding-block: spacer('xxs');
      padding-inline: spacer('s');
      text-decoration: none;

      &:hover {
        color: color.adjust(color('primary', $only-color: true), $lightness: 40%);
      }
    }
  }

  svg {
    --size: 1em;
    block-size: var(--size);
    color: color('primary');
    inline-size: var(--size);
  }
}
<div
    @click.outside="open = false"
    @keyup.escape.window="open = false"
    class="lang-switcher"
    x-data="{ open: false }"
>
    <button
        @click="open = ! open"
        :aria-expanded="open"
        aria-label="English"
        aria-expanded="false"
        class="lang-switcher__control"
        type="button"
    >
        en
        <svg aria-hidden="true" fill="none" focusable="false" height="24" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" stroke="currentColor" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
            <polyline points="6 9 12 15 18 9"></polyline>
        </svg>
    </button>
    <ul
        class="lang-switcher__panel"
        x-cloak
        x-trap="open"
        x-show="open"
        x-transition.origin.top.leff
    >
        <li>
            <a hreflang="de" href="/de/" aria-label="German">de</a>
        </li>
        <li>
            <a hreflang="fr" href="/fr/" aria-label="French">fr</a>
        </li>
    </ul>
</div>

Lang Switcher

On this page

A plain dropdown language switcher.

Technical Details

  • You can open the dropdown upward by using the .lang-switcher--upward modifier. It's a good option to display the lang switcher at the bottom of your footer.
  • It uses Alpine.js to manage the interaction and states.
  • The language switcher is designed with accessibility in mind. It can be closed using the esc key, providing a familiar interaction for users. Additionally, it traps the cursor, ensuring that users stay within the switcher until they make a selection.
  • You should set the hreflang and aria-label properly.

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our extensive UI library built with Spruce CSS.

Blog

Read about front-end development and concepts of Spruce CSS.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.