Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Custom class name completion contexts #7553

Closed
bradlc opened this issue Jun 16, 2020 · 74 comments
Closed

Custom class name completion contexts #7553

bradlc opened this issue Jun 16, 2020 · 74 comments

Comments

@bradlc
Copy link
Contributor

bradlc commented Jun 16, 2020

There has been quite a few requests for the extension to support class name completions in contexts other than a standard class(Name) attribute.

Some examples:

I just wanted to consolidate all of these requests into a single issue that can be tracked more easily, as I think the solution could be the same for each of them.

I am reluctant to hard-code each of these cases into the extension because none of them are "official" methods of using Tailwind, and it may become a maintenance burden.

However, I am open to the idea of adding a user setting which would allow the definition of custom regular expressions. For example for tailwind-rn your regular expression might be something like: /\btailwind\([^)]+/ig

If you're interested in this feature feel free to "watch" this issue for updates, and post any comments/suggestions you may have.

@danielkcz
Copy link

The twin.macro also supports <div tw="text-black" />, can you add it to the list, please?

@tobkle
Copy link

tobkle commented Jun 16, 2020

Thank you @bradlc. Would it make sense to have those regex's as an array in the vscode settings? It'll be more extensible though. I think it's that what you meant with user settings. That's a good idea.

@bradlc
Copy link
Contributor Author

bradlc commented Jun 17, 2020

The twin.macro also supports <div tw="text-black" />, can you add it to the list, please?

Added!

Thank you @bradlc. Would it make sense to have those regex's as an array in the vscode settings? It'll be more extensible though. I think it's that what you meant with user settings. That's a good idea.

Yes exactly. It would be a user setting.

@johot
Copy link

johot commented Jun 29, 2020

In my case I pull some tailwind class combinations into my own config objects. Could one solution be to simply add a comment above these variables and make it work?

For example a // @tw comment like below:

const theme: Theme = {
    borders: borders,
    input: {
      // @tw
      default:
        " border rounded-lg bg-white shadow-light-md  " + borders.default,
    }
}

@sudomf
Copy link

sudomf commented Jul 2, 2020

It would be great to have an option to use custom regex in the user settings. I'm using tailwind in React and Svelte as components props. So, have typesafe and the plugin hints with that would be awesome.

@will-t-harris
Copy link

Hey @bradlc, I'd be interested in trying to help with this issue. Where would you suggest I start digging into the code?

@dylanirlbeck
Copy link

@bradlc Can we get an update? @will-t-harris volunteered to help with this feature but has not yet gotten a response. Thanks in advance!

@wfischer42
Copy link

Here's a silly temporary hacky solution:

Screen Shot 2020-08-13 at 5 29 09 PM

If you make a snippet for the commented class lines then delete them when you're done, it adds very little overhead to get auto-complete.

@wfischer42
Copy link

I managed to have some success by using this regex in the following matchers:

/((?:\b|:)(class(?:Name)?|tw)=?['"`{])/gi

https://github.com/tailwindlabs/tailwindcss-intellisense/blob/81446acdb382922c6989d74710305ebfbe68cd4e/src/lsp/providers/completionProvider.ts#L129
https://github.com/tailwindlabs/tailwindcss-intellisense/blob/81446acdb382922c6989d74710305ebfbe68cd4e/src/lsp/util/find.ts#L132

I haven't worked on VS Code extensions before, but you can try it locally by running npm run dev then hitting F5 in VSCode to launch an Extension Development Host window. From there, load up a project with a tailwind.config file to start the extension. You'll need to disable the marketplace extension first.

I also don't know regex very well. This is just an experiment to figure out where to make the change. The goal, of course would be to find matches with existing regex and a list of expressions from settings, but I haven't experimented with that yet.

One thing I've noticed is that this doesn't work, but should...

class=`<should autocomplete>`
tw=`<should autocomplete>`

Any thoughts on fixing the backtick issue? Also, specific regex to match some of the example strings would be helpful!

Hope this is helpful @will-t-harris!

@trevyn
Copy link

trevyn commented Aug 17, 2020

@vxna
Copy link

vxna commented Sep 1, 2020

@bradlc
Copy link
Contributor Author

bradlc commented Nov 30, 2020

Hey everyone. v0.5.1 of the extension has a new experimental setting: tailwindCSS.experimental.classRegex

This setting allows you to specify additional places where completions should be triggered. Hovers and linting are not currently supported.

Here is an example:

"tailwindCSS.experimental.classRegex": [
  ["classnames\\(([^)]*)\\)", "'([^']*)'"]
]

Each item in the classRegex array is an array with two regular expressions. The first is an expression to match the container, and the second is to match the class lists inside that container. Let's use the classnames library as an example:

<div className={classnames('bg-red-500', 'uppercase')}>

The container is the classnames argument list: 'bg-red-500', 'uppercase'. This container can contain multiple class lists, in this case bg-red-500 and uppercase.

Both regular expressions must contain exactly one capture group.

You can also specify a single regular expression for simpler containers that contain a single class list:

"tailwindCSS.experimental.classRegex": [
  "tw`([^`]*)"
]

So if you wanted both of these new contexts your setting might look like this:

"tailwindCSS.experimental.classRegex": [
  "tw`([^`]*)",
  ["classnames\\(([^)]*)\\)", "'([^']*)'"]
]

If anyone has any questions or feedback let me know 👍

Please note that this feature is experimental and could change at any time, and enabling it could affect the performance of the extension.

@catalinmiron
Copy link

@MartsTech this should work for React Native

"tailwindCSS.experimental.classRegex": [
    ["tailwind|yourModule\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
],

usage

<View style={tailwind('m-2')} />
<View style={tailwind("m-2")} />
<View style={tailwind(`m-2`)} />
<View style={[styles.myStyle, tailwind("m-2")]} />
<View style={[{padding: 20}, tailwind("m-2")]} />
<View style={[tailwind(`m-2`), tailwind(`p-2`)]} />

@statusunknown418
Copy link

@catalinmiron isn't working for me, I'm using the package tailwind-react-native-classnames and used the Regex you showed but doesn't work. Also, how can I make Regex that accepts a syntax like this:
tw`m-1 <more_classnames>`

@gaelollivier
Copy link

Sharing my config as well as I didn't find it mentioned before: I wanted to allow setting up classes in objects at the beginning of my components, like this:

const fieldStyles = /*tw*/ {
    default: {
        label: 'py-2',
        input: 'px-3 py-2 font-medium text-sm',      
    },    
    inline: {
        label: 'py-2',
        input: 'px-3 py-2 font-medium text-sm',      
    },    
};

I didn't want to use a function or tagged string literal to avoid the need for an additional import, so I opted for a comment tag: /*tw*/. The assumption is the block should end with ; (and there should be no ; within the classes declarations).
Here is the config:

"tailwindCSS.experimental.classRegex": [["/\\*tw\\*/ ([^;]*);", "'([^']*)'"]]

@slamuu
Copy link

slamuu commented Sep 18, 2021

Wanted to add for those that encounter a weird issue that codemonkey800 mentioned above, where autocompletion or tooltip stops functioning after a certain number of lines/characters, is actually due to the limit on the custom regex matchers

@Axedyson
Copy link

I'm not good with regex development, any idea of what regex could match this:

const InputFieldClasses = ctl(`
  py-2
  px-3
  w-full
  rounded-md
  border
  border-gray-300
  focus:border-primary
  focus:ring-1
  focus:ring-primary
  transition
  focus:outline-none
`);

Seems like this works: "ctl\\(([^)]*)\\)", but I can't seem to make string interpolation work:

const InputFieldClasses = ctl(`
  py-2
  px-3
  w-full
  rounded-md
  border
  border-gray-300
  focus:border-primary
  focus:ring-1
  focus:ring-primary
  focus:outline-none
  ${someBooleanValue && "transition"}
  ${someBooleanValue ? "transition" : "some other class"}
`);

Thanks!

@edgarasben
Copy link

In my case I want to match every attribute ending with Class. This worked for me: "tailwindCSS.experimental.classRegex": ["[a-zA-Z]*Class='([^']+)'"]

@deadcoder0904
Copy link

I am currently using Skeletonhttps://github.com/dvtng/react-loading-skeleton/

It has containerClassName which is most common in other packages as well. Would love support for this as well.

@bigodel
Copy link

bigodel commented Dec 2, 2021

Did anyone manage to get the experimental classRegex working with ClojureScript? I created the following classRegex to test if it works for a simple regex, just a class on a div:

 "tailwindCSS.experimental.classRegex": [
        ":div\\.(\\w*)"
  ]

When trying to add a class to a simple [:div "Hello"] like [:div.text-3xl "Hello"], there was no Intellisense help.

Maybe the following setting is also not correct:

 "tailwindCSS.includeLanguages": {
        "clojurescript": "html"
  },

Is "clojurescript" the correct identifier? Maybe "html" is not the correct choice, too, but the other mentioned examples "css" and "javascript" did not work either.

hey, i didn't need to set it in the includeLanguages setting, i got it working only by setting the regexp to "class\\s+\"([^\"]*)\"". granted it only works on :class "..." syntax, and it doesn't cover when the class is set using a vector, but i'm trying to make it work with that. though keep in mind i'm on Emacs, using the lsp-tailwindcss client, which states that it ignores includeLanguages in favour of its own activation mechanism.

with that in mind, i'm also trying to make it work with the element.class-1.class-2 syntax. for reference to those unfamiliar with Clojure(Script) and its hiccup syntax, you can specify elements as simple vectors, using hash maps for the attributes of an element. so

<div class="p-2 bg-white">
  <h1>Hello world!</h1>
</div>

can be written as

[:div {:class "p-2 bg-white"}
 [:h1 "Hello world!"]]

now an alternative to writing the class in a hash map like the above is to specify it like so:

[:div.p-2.bg-white
  [:h1 "Hello world!"]]

hence i tried setting the class regex to match this particular case as well as "\[:(\\w+-?)\.([^\\s]\.?)*" -- this is simplified because the we can also specify ids with this short syntax, but here i'm only considering the case where you are writing only classes, like presented in the previous code block. but when trying to auto complete, the server always times out and doesn't send any completion candidates. i don't know if this is an issue with the server itself, or with the client, but i believe the former to be case, though if i'm mistaken please let me know and i can open an issue on the Emacs client's repo. i've toyed on RegExr and the regular expression appears to be matching correctly.

the fact that it works with the more usual, :class "..." syntax is already amazing, nonetheless!!

@OmkarK45
Copy link

OmkarK45 commented Dec 3, 2021

"tailwindCSS.experimental.classRegex": [
    ["tailwind|yourModule\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
],

Does not work, unfortunately.
What I tried

  • Restarting IDE
  • Reloading Window

@ardiansyaherwin
Copy link

Hi, is there any config to achieve getting classname suggestion if using external file in array format.

here's my current setup on using tailwind to avoid long classnames in a div.

the component:

import { FunctionComponent } from "react";
import styles from "style-classes/components/Header";

const Header: FunctionComponent = () => <div className={styles.header} />;
export default Header;

the style file:

const styles = {
  header: [
    'border-b',
    'border-charcoal-200',
    'flex w-full',
  ].join(' '),
};

export default styles;

@anisimovv
Copy link

Hi, is there any config to achieve getting classname suggestion if using external file in array format.

here's my current setup on using tailwind to avoid long classnames in a div.

the component:

import { FunctionComponent } from "react";
import styles from "style-classes/components/Header";

const Header: FunctionComponent = () => <div className={styles.header} />;
export default Header;

the style file:

const styles = {
  header: [
    'border-b',
    'border-charcoal-200',
    'flex w-full',
  ].join(' '),
};

export default styles;

I managed to make it work using className as a constant name

const className = { button: "text-black" }

and then reference it like

<button className={className.button}>button text</button>

@rottmann
Copy link

Any solution for why it run only once? (see #7553)

@ardiansyaherwin
Copy link

Hi, is there any config to achieve getting classname suggestion if using external file in array format.
here's my current setup on using tailwind to avoid long classnames in a div.
the component:

import { FunctionComponent } from "react";
import styles from "style-classes/components/Header";

const Header: FunctionComponent = () => <div className={styles.header} />;
export default Header;

the style file:

const styles = {
  header: [
    'border-b',
    'border-charcoal-200',
    'flex w-full',
  ].join(' '),
};

export default styles;

I managed to make it work using className as a constant name

const className = { button: "text-black" }

and then reference it like

<button className={className.button}>button text</button>

Hi, I guess that's not what I'm looking for, instead I'd like to have the suggestion list shown when I edited the style file not the component file

@anisimovv
Copy link

Hi, is there any config to achieve getting classname suggestion if using external file in array format.
here's my current setup on using tailwind to avoid long classnames in a div.
the component:

import { FunctionComponent } from "react";
import styles from "style-classes/components/Header";

const Header: FunctionComponent = () => <div className={styles.header} />;
export default Header;

the style file:

const styles = {
  header: [
    'border-b',
    'border-charcoal-200',
    'flex w-full',
  ].join(' '),
};

export default styles;

I managed to make it work using className as a constant name
const className = { button: "text-black" }
and then reference it like
<button className={className.button}>button text</button>

Hi, I guess that's not what I'm looking for, instead I'd like to have the suggestion list shown when I edited the style file not the component file

Screenshot 2021-12-23 at 14 03 45

it works in a separate file. The only thing the constant name should be "className". Then just import it into your component file.

I know, it is a workaround, but it works for me)

@ardiansyaherwin
Copy link

@anisimovv wow, thanks a lot! it works great!

@scalavision
Copy link

Is it possible to give a better explanation of how this regex works?

My guess is that you do it like this:

"<prefix><start-char>([^<end-char>]*)"

I am writing css like this in may own dsl in scala:

cls"bg-blue-200"

I saw this in stack overflow for the cntl dsl:

 "tailwindCSS.experimental.classRegex": [
            "cntl`([^`]*)", // cntl`...`
        ],

So I tried:

  "cls\"([^\"]*)"

and it works, but I also need to add "includeLanguages" for scala, and map it to html like this:

"tailwindCSS.includeLanguages": {
    "scala": "html"

I tried also to add "cls" to tailwindCSS.classAttributes, but that did not work however. I guess it is because I skip the = sign in my dsl.

With a bit of documentation I think this really should be added as a non-experimental feature. It works really great for me!

@drgubo
Copy link

drgubo commented Feb 4, 2022

In (Drupal) TWIG templates, element classes are often defined as a variable this way:
{% set classes = [ 'node', view_mode ? 'node--view-mode-' ~ view_mode|clean_class, ] %}
And then added to the element this way:
<article{{ attributes.addClass(classes) }}>

These expressions seem to work in both places for tailwind classes typed after an opening apostrophe:
["classes =.+\\[([^\\]]*)\\]","'([^']*)'"], ["addClass\\(([^\\)]*)\\)","'([^']*)'"]

(I'm sure they can be improved, though.)

@xavianaxw
Copy link

For styled-components, where your code looks like this.

import styled from 'styled-components';

const TestWrapper = styled.div.attrs({
  className: 'bg-blue py-12',
})``;

add this to your settings.json

"tailwindCSS.experimental.classRegex": [
    "className\\: '([^']*)'",
  ]

@tailwindlabs tailwindlabs locked and limited conversation to collaborators Feb 21, 2022
@bradlc bradlc converted this issue into discussion #7554 Feb 21, 2022
@bradlc bradlc transferred this issue from tailwindlabs/tailwindcss-intellisense Feb 21, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests