prettier / prettier/prettier

styled-components css attribute quotes are inconsistent

Open
#10,638 2 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:multiparser lang:css/scss/less lang:javascript
Dominant language
JavaScript
Stars
52.3k
Forks
5k
Avg merge
19h 2m
Merged PRs (30d)
117

Description

Prettier 2.2.1
Playground link

--parser babel
--print-width 100
--tab-width 4
--single-quote

Input:

import { css } from 'styled-components';
import token from 'styled-token';
import { disabledMixin } from '../disabledMixin';
import { spacingMixin } from '../spacingMixin';
import { typographyMixin } from '../typographyMixin';

/** @class LabelMixin */
/** @method */
export const LabelMixin = props => {
    const { size } = props;
    return token(
        {
            fontType: `Label.fontTypes.${size}`,
            optionalColor: 'Label.optionalColor',
            asteriskColor: 'Label.asteriskColor',
        },
        tokens => css`                                                                                                                                                                                                                        
            &:not([aria-disabled="true"]) {                                                                                                                                                                                                   
                cursor: pointer;                                                                                                                                                                                                              
            }                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                              
            ${typographyMixin({ fontType: tokens.fontType, ...props })}                                                                                                                                                                       
                                                                                                                                                                                                                                              
            &[data-required="true"]:after {                                                                                                                                                                                                   
                content: '\\00a0*';                                                                                                                                                                                                           
                color: ${tokens.asteriskColor};                                                                                                                                                                                               
            }                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                              
            &[data-optional="true"]:after {                                                                                                                                                                                                   
                content: '\\00a0(optional)';                                                                                                                                                                                                  
                color: ${tokens.optionalColor};                                                                                                                                                                                               
                font-weight: normal;                                                                                                                                                                                                          
            }                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                              
            &[aria-disabled="true"] {                                                                                                                                                                                                         
                ${disabledMixin({ ...props, disabled: true })}                                                                                                                                                                                
            }                                                                                                                                                                                                                                 
                                                                                                                                                                                                                                              
            ${spacingMixin(props)}                                                                                                                                                                                                            
        `
    )(props);
};

Output:

import { css } from 'styled-components';
import token from 'styled-token';
import { disabledMixin } from '../disabledMixin';
import { spacingMixin } from '../spacingMixin';
import { typographyMixin } from '../typographyMixin';

/** @class LabelMixin */
/** @method */
export const LabelMixin = (props) => {
    const { size } = props;
    return token(
        {
            fontType: `Label.fontTypes.${size}`,
            optionalColor: 'Label.optionalColor',
            asteriskColor: 'Label.asteriskColor',
        },
        (tokens) => css`
            &:not([aria-disabled='true']) {
                cursor: pointer;
            }

            ${typographyMixin({ fontType: tokens.fontType, ...props })}

            &[data-required="true"]:after {
                content: '\\00a0*';
                color: ${tokens.asteriskColor};
            }

            &[data-optional='true']:after {
                content: '\\00a0(optional)';
                color: ${tokens.optionalColor};
                font-weight: normal;
            }

            &[aria-disabled='true'] {
                ${disabledMixin({ ...props, disabled: true })}
            }

            ${spacingMixin(props)}
        `
    )(props);
};

Expected behavior:

When using attribute selectors, in three of the four cases above, double quotes are switched to single quotes, and in the last case, no changes are made.

-&:not([aria-disabled="true"]) {
+&:not([aria-disabled='true']) {
 &[data-required="true"]:after { 
-&[data-optional="true"]:after {
+&[data-optional='true']:after {
-&[aria-disabled="true"] {
+&[aria-disabled='true'] {

I would expect these to be consistent.

-&:not([aria-disabled="true"]) {
+&:not([aria-disabled='true']) {
-&[data-required="true"]:after { 
+&[data-required='true']:after { 
-&[data-optional="true"]:after {
+&[data-optional='true']:after {
-&[aria-disabled="true"] {
+&[aria-disabled='true'] {

Ideal behavior:

Ideally I would like my JS to use single quotes and my embedded CSS to always use double quotes, but it looks like there isn't an option to format CSS differently. While I preferred double quotes in CSS, I was OK with single until I tried to update styled-components and found that jest-styled-components now breaks when using single quotes. I have a couple ideas on how to workaround this (not sure if you have any other ideas):

  1. I could turn off embedded language formatting (but then I would lose the formatting altogether)
  2. I could switch to always using double quotes
  3. I could use different config for my styled-components mixins that always uses double quotes

It would be great if there was a way to provide different prettier options for embedded languages.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the reported output from the linked Playground using the Babel parser, Prettier 2.2.1, and the shown formatting options. Compare the four embedded CSS attribute selectors; done means their quote handling is consistent while preserving the surrounding JavaScript formatting.

Written by the indexing model from the issue text.

Assessment

Tech stack
css, javascript
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.