Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>LuauX LSPNew to Visual Studio Code? Get it now.
LuauX LSP

LuauX LSP

Ryan Cundiff

|
4 installs
| (0) | Free
Editor support for .luaux — highlighting, completion and diagnostics for LuauX, JSX-style markup for Luau
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

LuauX LSP

Editor support for .luaux

Syntax highlighting and a language server for LuauX — JSX syntax in Luau.

CI

Overview

Highlighting works on its own. Completion, diagnostics, hover and the rest come from luaux-lsp, which this extension starts if it can find one, and which ships inside it so that it can.

Given a file being written:

local function Card (props)
  return (
    <Frame Size={UDim2.fromScale(1, 1)}>
      <TextLabel Text={props.Title} />
    </Frame>
  )
end

local card = <Card Title="Hello" />

Typing <Fra offers Frame and every other creatable class, alongside the components bound in the file. <TextLabel offers that class's properties and events. </ closes whatever is open. All of it works while the file does not compile, because a file being typed never does.

Hovering <Card> says it resolved to a component and where. That is something create("Frame") cannot tell you, because by then it is a string.

A misspelling is reported where it was written, with a one-click fix that inserts the project's own spelling:

<Frmae> is not a Roblox class and is not defined
  → Change to <Frame>

What it does

On its own, with no other extension and no second process:

  • Diagnostics from the compiler, with help as related information
  • Quick fixes: <Frmae> → <Frame>, and unknown properties → the nearest real ones
  • Completion: tag names, a class's properties and events, and closing tags, all alias-aware, and all working on files that do not compile
  • Hover on a tag: whether it resolved to a Roblox class or a component, and where that component is bound
  • Go-to-definition on a component tag
  • Document symbols: the element tree as an outline
  • Semantic tokens telling an intrinsic apart from a component, which a regex grammar cannot know
  • Rename on a tag pair, <Frame>…</Frame> together

With luau-lsp installed, everything inside a captured { … } as well:

  • Hover, completion, definition, references, signature help, inlay hints
  • Its type errors, merged with ours and mapped back onto the .luaux

Using it with luau-lsp

The two extensions do not conflict. This one claims .luaux and only .luaux; luau-lsp keeps .luau. Install both and your existing luau-lsp.* settings are read and passed through, so definition files and FFlags are configured once rather than twice.

Without luau-lsp, everything above still works except the parts that needed Luau types. Nothing fails, and the LuauX output channel says what it found.

src/App.luaux          ← you edit this, and it is what the editor shows
  │
  ├─ luaux-lsp         ← owns the file, answers markup questions
  │    └─ luau-lsp     ← stock binary, unmodified, answers Luau questions
  │
  └─ luaux build       ← the compiler, unchanged

The generated build/App.luau is the path the build already writes, so require resolves, the rojo sourcemap lines up, and .luaurc aliases apply. As far as luau-lsp is concerned, this is the file it would have analysed anyway.

Configuration

Every setting is optional.

Setting Description
luaux.server.path Path to luaux-lsp. Empty searches PATH, then rokit's tool storage, then the bundled copy.
luaux.luauLsp.path Path to luau-lsp. Empty searches the same places. Without one, LuauX answers nothing that needed Luau types.
luaux.autoClosingTags Close a tag as you finish opening it: typing <Frame> puts </Frame> after the cursor. Default true.
luaux.trace.server Log traffic between the editor and the LuauX server. off, messages, or verbose.

LuauX: Restart Server restarts it from the command palette. The LuauX output channel reports which binaries were chosen, which is the first place to look if something is missing.

How the highlighting works

.luaux is Luau plus LuauX, so the base grammar includes source.luau wholesale and the LuauX rules arrive as an injection.

Injection rather than layering is not a stylistic choice. A layered grammar stops applying once source.luau enters one of its own begin/end blocks, and return (<Frame/>) puts the LuauX inside a parenthesised expression, so the most common form of all was the broken one.

The grammar stays even though the server emits semantic tokens, because it is the fallback for whenever the server is starting, crashed or absent. Highlighting must never depend on a process being alive.

Known limitation

TextMate is regex-only, so it cannot do the previous-token analysis the compiler uses to tell <Frame/> from a < b. The heuristic is that a tag is < immediately followed by a name and then whitespace, / or >.

a < b is safe, because of the space. a <b will highlight as a tag. That is cosmetic: the compiler remains the authority on what is LuauX, and the server uses the compiler's own rule rather than this one.

Contributing

Source, build instructions and the test suites are at luau-xml/lsp. Bugs and requests go to the issue tracker.

Credits

Built on luau-lsp by JohnnyMorganz, which answers every Luau question here, unmodified, unforked, and unaware that LuauX exists.

This project is not affiliated with or endorsed by luau-lsp.

License

MIT.

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft