Styling Shopify's s-link & s-clickable: A Developer's Deep Dive

Taming the s-link and s-clickable Beast: A Styling Saga

So, you're diving into Shopify embedded app development and want to make those and components truly your own? You're not alone! I stumbled upon a fascinating discussion in the Shopify Community where @dvendy was wrestling with the exact same issue: overriding the default Polaris styles with Tailwind CSS. It turns out, it's a bit of a journey, but definitely achievable.

The Shadow DOM Challenge

The core problem? These components live inside the Shadow DOM. If you're not familiar, Shadow DOM essentially creates a mini-encapsulated world for the component's styling. Regular CSS, even with !important, often can't pierce through. As @dvendy discovered, attempts to override the styles directly were hitting a wall.

Here's what @dvendy tried:

  • text-decoration: none
  • background: transparent !important
  • targeting s-link, s-clickable
  • ::part() selectors (e.g. ::part(activator))
  • wrapping content in divs
  • removing focus/outline styles

Despite all that effort, the default hover/pressed gray state stubbornly persisted.

Understanding Shopify's Intent

As @anmolkumar pointed out, Shopify's philosophy here is key. They intend for you to either embrace Polaris styling fully *or* go completely custom. Mixing and matching can be tricky.

Shopify’s intent is:
Use Polaris comp Polaris styling
Want full custom UI = use your own components + navigation

The Recommended Path: React Router to the Rescue

So, how do you break free from the Polaris styling if you want full control? The suggested solution, and the one that seems most robust, involves leveraging React Router (or the Navigation API directly) instead of relying solely on and for styling.

Here's the gist:

  • Ditch the / for visual styling: Think of them primarily for their navigation behavior.
  • Embrace React Router: Use components or the navigate() function for routing within your app.
  • Wrap and Style: Wrap your own styled components around the navigation logic. This gives you 100% visual control using Tailwind or any other CSS framework.

For example, instead of:

My Custom Button

You'd do something like:


  

Handling Internal Routes and Authentication

One concern @dvendy raised was about losing the auth session when navigating to internal routes like /page2. This is a crucial point! Using React Router correctly within your embedded app should maintain the session. Make sure you're not accidentally triggering a full page reload, which would indeed break the session.

Here's a reminder about internal routes from @anmolkumar:

For internal routes like /page2 inside an embedded app, don’t use with target="_top"
Use React Router instead:

Go to Page 2 or programmatically: navigate("/page2"); target="_top"` should only be used when redirecting to Shopify Admin (e.g. `shopify://admin/products.

Navigating to Shopify Admin

When you *do* need to link to a specific Shopify Admin page (like the products page), that's where the shopify://admin/ protocol comes in handy. For example:

Products page

This will correctly open the products page within the Shopify Admin.

Ultimately, styling Shopify's web components requires understanding their architecture and Shopify's intended usage. While directly overriding the default styles can be challenging (thanks to Shadow DOM), using React Router and custom components provides the flexibility to create a truly unique and branded experience within your embedded app. It's all about choosing the right tools for the job and embracing the Shopify ecosystem's best practices. Good luck, and happy coding!

Share:

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools