Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Radio input checked state #786

Closed
mkitzmann opened this issue Jun 13, 2022 · 2 comments
Closed

Radio input checked state #786

mkitzmann opened this issue Jun 13, 2022 · 2 comments
Assignees
Labels
feature Feature requests.

Comments

@mkitzmann
Copy link

What issue are you having?

It is difficult to theme the checked state of the Radio Input since it uses an SVG element. So even for minor adjustments, the whole SVG needs to be overwritten.
https://github.com/shoelace-style/shoelace/blob/next/src/components/radio/radio.ts

Describe the solution you'd like

Instead of an SVG the checked state could be styled using CSS. Either by using a border styling or pseudo element. This would allow for the checked state to be easily customizable since pseudo elements and classes can be themed using CSS Parts.

Example using border styling:

input[type="radio"]:checked {
  border: 6px solid  var(--sl-color-primary-500);
}

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#styling_radio_inputs

Example using pseudo elements:

input[type="radio"]::before {
  content: "";
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background-color: white;
}

input[type="radio"]:checked {
  background-color: var(--sl-color-primary-500);
  border-color: var(--sl-color-primary-500);
}

Describe alternatives you've considered

We considered swapping the entire SVG element using the CSS Part provided (checked-icon).

@mkitzmann mkitzmann added the feature Feature requests. label Jun 13, 2022
@claviska
Copy link
Member

SVG use is consistent in radio and checkbox, so I'd like to maintain that consistency and find a better solution that works for both (and future) components.

A couple ideas:

  1. We can use slots where the fallback content is the current SVG. This would let you slot in your own SVG or any HTML you wanted. The drawback is you'd need to slot it in for every form control you want to restyle, which isn't ideal.

  2. We can add a part to the SVGs that would let you target it via CSS. Then you can hide the SVG and restyle its container, which is similar to what you're suggesting above.

<span part="checked-icon" class="radio__icon">
  <svg part="checked-icon-image" viewBox="0 0 16 16">
    <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
      <g fill="currentColor">
        <circle cx="8" cy="8" r="3.42857143"></circle>
      </g>
    </g>
  </svg>
</span>

Again, I'm reluctant to get rid of the SVG as it keeps things consistent and it's much easier to style things like checkmarks with vector images than CSS hacks.

@claviska
Copy link
Member

We can use slots where the fallback content is the current SVG.

After thinking about this more, there's only one instance of this in the library (Image Comparer) and I'm thinking of removing it to prevent such a pattern from propagating. It's inelegant, and a better solution for replacing default SVGs would be some kind of registry similar to Icon Libraries or the Animation Registry. However, I'm not convinced this is something many users are going to want, so it's probably not worth the extra boilerplate, modules, and confusion it will take to pull that off.

We can add a part to the SVGs that would let you target it via CSS. Then you can hide the SVG and restyle its container, which is similar to what you're suggesting above.

This is the approach I took. I removed the <span> elements that wrapped the SVGs in both Checkbox and Radio and moved the checked-icon parts to the SVG itself to remove the extra markup and allow you to target the SVG directly.

After looking at some other components (e.g. the caret SVG in Button, the ring SVG in Progress Ring, and the spinner SVG in Spinner), all components are consistently applying parts so you can override them by hiding the SVG and styling the control part.

<sl-checkbox>Checkbox</sl-checkbox>

<style>
  sl-checkbox[checked]::part(checked-icon) {
    display: none;
  }

  sl-checkbox[checked]::part(control) {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' part='checked-icon' class='checkbox__icon' viewBox='0 0 16 16'%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' stroke-linecap='round'%3E%3Cg stroke='lime' stroke-width='2'%3E%3Cg transform='translate(3.428571, 3.428571)'%3E%3Cpath d='M0,5.71428571 L3.42857143,9.14285714'%3E%3C/path%3E%3Cpath d='M9.14285714,0 L3.42857143,9.14285714'%3E%3C/path%3E%3C/g%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
  }
</style>

CleanShot 2022-06-29 at 08 17 42@2x

This example uses the same SVG that's baked into checkbox, but you can use any SVG. Alas, we can't use ::before and ::after along with ::part(), so this does limit you a bit. However, you can also take advantage of clip-path to do some interesting things.

<sl-checkbox>Checkbox</sl-checkbox>

<style>
  sl-checkbox[checked]::part(checked-icon) {
    display: none;
  }

  sl-checkbox[checked]::part(control) {
    background: red;
    clip-path: polygon(
      20% 0%,
      0% 20%,
      30% 50%,
      0% 80%,
      20% 100%,
      50% 70%,
      80% 100%,
      100% 80%,
      70% 50%,
      100% 20%,
      80% 0%,
      50% 30%
    );
  }
</style>

CleanShot 2022-06-29 at 08 16 45@2x

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature requests.
Projects
None yet
Development

No branches or pull requests

2 participants