{"record":{"id":"bbc7639d5283026e","repo":"honojs/hono","slug":"invalid-jsx-tag-name-tag","errorCode":null,"errorMessage":"Invalid JSX tag name: ${tag}","messagePattern":"Invalid JSX tag name: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/jsx/base.ts","lineNumber":179,"sourceCode":"\nexport type Child =\n  | string\n  | Promise<string>\n  | number\n  | JSXNode\n  | null\n  | undefined\n  | boolean\n  | Child[]\nexport class JSXNode implements HtmlEscaped {\n  tag: string | Function\n  props: Props\n  key?: string\n  children: Child[]\n  isEscaped: true = true as const\n  constructor(tag: string | Function, props: Props, children: Child[]) {\n    if (typeof tag !== 'function' && !isValidTagName(tag)) {\n      throw new Error(`Invalid JSX tag name: ${tag}`)\n    }\n    this.tag = tag\n    this.props = props\n    this.children = children\n  }\n\n  get type(): string | Function {\n    return this.tag as string\n  }\n\n  // Added for compatibility with libraries that rely on React's internal structure\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  get ref(): any {\n    return this.props.ref || null\n  }\n\n  toString(): string | Promise<string> {\n    const render = () => {","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/honojs/hono/blob/e2740d5a1bd0b4254e517e3af8b60789284bc7bd/src/jsx/base.ts#L161-L197","documentation":"Hono's JSX runtime validates tag names when constructing a JSXNode: a tag must either be a function component or a string that is a valid HTML/SVG element name or a valid custom-element name. If it's a string that fails isValidTagName (e.g. contains invalid characters, is empty, or isn't a recognized element/custom element), this error is thrown.","triggerScenarios":"Rendering `<my-component>` where the string is not a valid custom-element name (must contain a hyphen with lowercase letters, like `my-element`); using a variable that is undefined/null/empty as a JSX tag (lowercase JSX tags that resolve to strings); dynamically building tag names like `<{\"div\" + suffix}>` producing an invalid name.","commonSituations":"Importing a component that resolves to undefined due to a missing/circular export and using it with a lowercase name; typos in intrinsic elements; attempting dynamic tag names with characters invalid in tag names (dots, spaces); forgetting that lowercase JSX tags referencing variables must be valid element or custom-element names.","solutions":["Check that the component variable is actually imported and not undefined; fix the import path/export name","If you meant a custom element, rename it to include a hyphen and valid characters (e.g. `my-element`)","If the tag is dynamic, validate/whitelist the string before interpolating it into JSX","Capitalize component variables so JSX treats them as function references, not tag names"],"exampleFix":"// before\nconst tag = someInput // e.g. 'My Widget' or undefined\nreturn <tag>hi</tag>\n// after\nconst tag = typeof someTag === 'string' && /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(someTag) ? someTag : 'div'\nreturn <tag>hi</tag>","handlingStrategy":"type-guard","validationCode":"const isValidElementName = (s: string) =>\n  /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(s) || /[A-Z]/.test(s)\nconst Tag = trustedTags.includes(name) ? name : 'div'","typeGuard":"const isJsxTag = (t: unknown): t is string | Function =>\n  typeof t === 'function' ||\n  (typeof t === 'string' && (HTMLElementTags.includes(t) || /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(t)))","tryCatchPattern":"null","preventionTips":["Verify component imports resolve to functions (avoid undefined lowercase tags)","Keep dynamic tag names in a whitelist","Name custom elements with a hyphen and lowercase alphanumeric characters"],"tags":["hono","jsx","validation","custom-element"],"backgroundTag":"invalid-jsx-tag-name","analyzedSha":"e2740d5a1bd0b4254e517e3af8b60789284bc7bd","analyzedAt":"2026-08-28T10:18:08.750Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}