isotropic-2022
Share
Blog
Search
Menu

How To Marquee Elements in 2024 (Best Practices)

By James LePage
 on August 9, 2022

How To Marquee Elements in 2024 (Best Practices)

By James LePage
 on August 9, 2022

This article will discuss the best ways to make moving marquee elements in modern web design.

A marquee is an infinite section of text and/or visual element (like images) that automatically scrolls horizontally.

image-38-9

Despite the official HTML <marquee> element being depreciated and strongly discouraged from being used, the overall effect of scrolling, continuous elements used to spice up a webpage is alive and well in 2024, appearing in many trendy websites.

Some still even use the Marquee element, which is still supported by all browsers despite (again) being discouraged from being used. For example, here's the classic bouncing DVD "screensaver" created with a HTML marquee.

<div> <marquee direction="down" height="100%" width="100%" behavior="alternate"> <marquee behavior="alternate"> <img height="80" src="/dvd.png" /> </marquee> </marquee> </div>

This isn't smart, but it still works. The reasons to avoid using this element in 2024 are clear:

  • It's not really accessible
  • It's 100% depreciated and support for it can (and probably will at some point) be removed
  • It was never a real HTML element to begin with (not a part of any standard)
HTML Marquee is depreciated - don't use it.
MDN docs' explanation on why you shouldn't use this element

However, we've always been fans of marquees at Isotropic.

Take a look at many of the trendy Awwwards websites and you'll see text, images or a combination of both moving horizontally, like so:

This Is A Demo Marquee

Of course, it's never a good idea to put mission critical information in scrolling or animated sections. But for something like the example above, it looks cool, differentiates the site, and makes it memorable. Use it wisely and in moderation.

Marquees are so cool, we even published a helpful tool that will automatically generate a "ticker" style section of scrolling text using CSS box shadows. It's cool, but I think that the approach discussed in this article is even better.

The code to make that marquee demo is sourced from this CodePen by Ryan Mulligan, which is (likely) the best way to make a marquee effect in 2024. He also writes about this code in his blog, https://ryanmulligan.dev/blog/css-marquee.

It's accessible (supports prefers-reduced-motion), infinite, allows for any type of html element, and is lightweight and easy to implement.

It's also made with 100% CSS and no JS.

<div class="marquee">
  <div class="marquee__group">
    <img src='https://images.unsplash.com/photo-1548199973-03cce0bbc87b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1583511666445-775f1f2116f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1586917383423-c25e88ac05ce?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1560743173-567a3b5658b1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1603232644140-bb47da511b92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
  </div>

  <div aria-hidden="true" class="marquee__group">
    <img src='https://images.unsplash.com/photo-1548199973-03cce0bbc87b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1583511666445-775f1f2116f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1586917383423-c25e88ac05ce?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1560743173-567a3b5658b1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1603232644140-bb47da511b92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
  </div>
</div>

<div class="marquee marquee--borders" style="--duration: 100s">
  <div class="marquee__group">
    <p>The Dogs of Unsplash</p>
    <p aria-hidden="true">The Dogs of Unsplash</p>
    <p aria-hidden="true">The Dogs of Unsplash</p>
  </div>

  <div aria-hidden="true" class="marquee__group">
    <p>The Dogs of Unsplash</p>
    <p>The Dogs of Unsplash</p>
    <p>The Dogs of Unsplash</p>
  </div>
</div>

<div class="marquee marquee--reverse">
  <div class="marquee__group">
    <img src='https://images.unsplash.com/photo-1546421845-6471bdcf3edf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1518378188025-22bd89516ee2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1571772805064-207c8435df79?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1602067340370-bdcebe8d1930?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1508948956644-0017e845d797?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''>
  </div>

  <div aria-hidden="true" class="marquee__group">
    <img src='https://images.unsplash.com/photo-1546421845-6471bdcf3edf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1518378188025-22bd89516ee2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1571772805064-207c8435df79?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1602067340370-bdcebe8d1930?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''>
    <img src='https://images.unsplash.com/photo-1508948956644-0017e845d797?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''>
  </div>
</div>
@import url("https://fonts.googleapis.com/css2?family=Corben:wght@700&display=swap");

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
}

body {
  --space: 2rem;

  display: grid;
  align-content: center;
  overflow: hidden;
  gap: var(--space);
  width: 100%;
  font-family: "Corben", system-ui, sans-serif;
  font-size: 1.5rem;
  line-height: 1.5;
}

.marquee {
  --duration: 60s;
  --gap: var(--space);

  display: flex;
  overflow: hidden;
  user-select: none;
  gap: var(--gap);
  transform: skewY(-3deg);
}

.marquee__group {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: var(--gap);
  min-width: 100%;
  animation: scroll var(--duration) linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .marquee__group {
    animation-play-state: paused;
  }
}

.marquee__group img {
  max-width: clamp(10rem, 1rem + 28vmin, 20rem);
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 1rem;
}

.marquee__group p {
  background-image: linear-gradient(
    75deg,
    hsl(240deg 70% 49%) 0%,
    hsl(253deg 70% 49%) 11%,
    hsl(267deg 70% 49%) 22%,
    hsl(280deg 71% 48%) 33%,
    hsl(293deg 71% 48%) 44%,
    hsl(307deg 71% 48%) 56%,
    hsl(320deg 71% 48%) 67%,
    hsl(333deg 72% 48%) 78%,
    hsl(347deg 72% 48%) 89%,
    hsl(0deg 73% 47%) 100%
  );
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.marquee--borders {
  border-block: 3px solid dodgerblue;
  padding-block: 0.75rem;
}

.marquee--reverse .marquee__group {
  animation-direction: reverse;
  animation-delay: calc(var(--duration) / -2);
}

@keyframes scroll {
  0% {
    transform: translateX(0);
  }

  100% {
    transform: translateX(calc(-100% - var(--gap)));
  }
}

Let's take a look at how this was created and why it's so great.

Here's an overview, before we look at all the code:

  • We can easily control the speed and direction of the scrolling effect. For speed, we set style="--duration: 100s" and for direction, we use a class of .marquee--reverse.
  • It's modular - you can have as many groups as you want by wrapping content in a div with the class of .marquee and the inner content with .marquee__group.
  • The sizing is responsive and fluid as it uses CSS variables and clamp.
  • It its accessible using aria labels and pausing if CSS' prefers-reduced-motion is set to reduced.
  • The movement is a standard CSS animation that uses keyframes (so you can pause on hover if you want). There's no JS at all.
  • It's also pretty copy/paste. Simply swap out your content, implement the HTML and CSS, and you'll have a cool little marquee.

It's really well done, and (imo) should be the standard way a marquee effect is implemented in 2024.

Here's the HTML:

<div class="marquee"> <div class="marquee__group"> <img src='https://images.unsplash.com/photo-1548199973-03cce0bbc87b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1583511666445-775f1f2116f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1586917383423-c25e88ac05ce?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1560743173-567a3b5658b1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1603232644140-bb47da511b92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> <div aria-hidden="true" class="marquee__group"> <img src='https://images.unsplash.com/photo-1548199973-03cce0bbc87b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1583511666445-775f1f2116f5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3MzQ&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1586917383423-c25e88ac05ce?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1560743173-567a3b5658b1?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ3NzU&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1603232644140-bb47da511b92?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> </div> <div class="marquee marquee--borders" style="--duration: 100s"> <div class="marquee__group"> <p>The Dogs of Unsplash</p> <p aria-hidden="true">The Dogs of Unsplash</p> <p aria-hidden="true">The Dogs of Unsplash</p> </div> <div aria-hidden="true" class="marquee__group"> <p>The Dogs of Unsplash</p> <p>The Dogs of Unsplash</p> <p>The Dogs of Unsplash</p> </div> </div> <div class="marquee marquee--reverse"> <div class="marquee__group"> <img src='https://images.unsplash.com/photo-1546421845-6471bdcf3edf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1518378188025-22bd89516ee2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1571772805064-207c8435df79?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1602067340370-bdcebe8d1930?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1508948956644-0017e845d797?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> <div aria-hidden="true" class="marquee__group"> <img src='https://images.unsplash.com/photo-1546421845-6471bdcf3edf?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1518378188025-22bd89516ee2?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1571772805064-207c8435df79?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDQ4MDE&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1602067340370-bdcebe8d1930?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> <img src='https://images.unsplash.com/photo-1508948956644-0017e845d797?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMjM4NDZ8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk0MDUyMTM&ixlib=rb-1.2.1&q=80&w=400' alt=''> </div> </div>

In the demo we can see three marquees. The first and third are reversed with the class of .marquee--reverse. They have a standard speed, and contain images.

The second (middle one) is all text, and implements borders with a custom class. It also has a slower duration set by the style attribute: style="--duration: 100s".

You'll also notice that there are essentially duplicates within the .marquee div, which are the same except with an aria tag.

This is to make the animation seamlessly infinite, while also being able to adapt to different viewport ratios (more on this when we look at the CSS).

This is made accessible with aria-hidden="true", which removes the duplicate content from the accessibility tree.

Also, the images are served directly from Unsplash. You may find this resource interesting: How To Generate Random Images By URL (Web Dev)

All in all, it's an elegant, simple HTML structure.

Now let's look at CSS ✨

And here's the CSS (pulled directly from the CodePen):

@import url("https://fonts.googleapis.com/css2?family=Corben:wght@700&display=swap"); * { box-sizing: border-box; } body { min-height: 100vh; } .demo_marquee-wrap { --demo-marquee_space: 2rem; display: grid; align-content: center; overflow: hidden; gap: var(--demo-marquee_space); width: 100%; font-family: "Corben", system-ui, sans-serif; font-size: 1.5rem; line-height: 1.5; } .marquee { --demo-marquee_duration: 60s; --demo-marquee_gap: var(--demo-marquee_space); display: flex; overflow: hidden; user-select: none; gap: var(--demo-marquee_gap); transform: skewY(-3deg); } .marquee__group { flex-shrink: 0; display: flex; align-items: center; justify-content: space-around; gap: var(--demo-marquee_gap); min-width: 100%; animation: scroll var(--demo-marquee_duration) linear infinite; } @media (prefers-reduced-motion: reduce) { .marquee__group { animation-play-state: paused; } } .marquee__group img { max-width: clamp(10rem, 1rem + 28vmin, 20rem); aspect-ratio: 1; object-fit: cover; border-radius: 1rem; } .marquee__group p { color:#29303e; } .marquee--borders { border-block: 3px solid #29303e; padding-block: 0.75rem; } .marquee--reverse .marquee__group { animation-direction: reverse; animation-delay: calc(var(--demo-marquee_duration) / -2); } @keyframes scroll { 0% { transform: translateX(0); } 100% { transform: translateX(calc(-100% - var(--demo-marquee_gap))); } }

We can see the following:

  • Everything is using REM, variables and clamp, meaning that the effect fluid and will react to screen size and browser settings.
  • The animation is 100% CSS. This is implemented with the "animation: scroll var(--duration) linear infinite;" line in .marquee__group. The animation is infinite, linear, and named scroll. The root duration is controlled by the --duration variable, which can be overwritten to control the speed of a specific group in the HTML markup (mentioned above).
  • Scroll is a basic transformation, translating X.
  • To reverse the animation, we simply have "animation-direction: reverse;' in the .marquee--reverse .marquee__group class.
  • We're making use of calc and --gap for the majority of the spacing. This makes things fluid and you can change Gap to suit your needs.
  • There's a skew (3%) effect that makes it diagonal, which can be removed to make it 100% horizontal.
  • It's accessible and responsible as it will not move if prefers-reduced-motion: reduce is set (learn how to test for that here).

Basically, it does everything really well, and is the best way to implement a scrolling marquee-like effect in 2024.

To implement, you simply add the HTML to your page, swap out the text/images, and add the CSS to your global styles.

You can play with the variables, but realistically this is pretty plug and play... there's not much you need to change!

Subscribe & Share
If you liked this content, subscribe for our monthly roundup of WordPress news, website inspiration, exclusive deals and interesting articles.
Unsubscribe at any time. We do not spam and will never sell or share your email.
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Cam
Cam
1 year ago

Ryan Mulligan's code looks to be almost identical to my CSS marquees created around a year ago and used in a load of high profile websites like Mr Beast's official online store :/

Article By
James LePage
Contributors/Editors
notloggedin
James LePage is the founder of Isotropic, a WordPress education company and digital agency. He is also the founder of CodeWP.ai, a venture backed startup bringing AI to WordPress creators.
We're looking for new authors. Explore Isotropic Jobs.
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram