npm install @michaelallenwarner/el-is
- TypeScript >= 5.0 (assuming you're using TypeScript)
import { elIs } from '@michaelallenwarner/el-is';
const htmlElement = document.querySelector('section'); // `HTMLElement | null`
if (elIs(htmlElement, 'SECTION')) {
// `htmlElement` now has type `HTMLElement & { tagName: 'SECTION' }`
}
const mathMlElement = document.querySelector('mrow'); // `MathMLElement | null`
if (elIs(mathMlElement, 'mrow')) {
// `mathMlElement` now has type `MathMLElement & { tagName: 'mrow' }`
}
const element = document.querySelector('.svg-path-element'); // `Element | null`
if (elIs(element, 'path')) {
// `element` now has type `Element & { tagName: 'path' }`
/*
But probably just do `if (element instanceof SVGPathElement)` instead!
Also, although `Element` will work as a type for the first parameter,
it's advisable to narrow it first to `HTMLElement`, `MathMLElement`, or `SVGElement`.
See Usage Notes below.
*/
}
The elIs()
function takes two arguments—a maybe-null
DOM element (el
) and a string literal (tagName
)—and returns the boolean
result of a simple el?.tagName === tagName
check, but with some TypeScript niceties described below.
But first, a quick warning: you probably should only use this function if the kind of element you're checking against doesn't have its own dedicated interface! For example, if you want to check whether el
is a link, I can't think of any reason not to just do if (el instanceof HTMLAnchorElement)
, so that the type-narrowing gives you all the properties and methods that come with the more specific interface (like HTMLAnchorElement.href
). The elIs()
function is really for testing whether an element is of a kind that doesn't have its own interface, like <section>
.
With that out of the way, here are the TypeScript niceties you get with elIs()
:
-
When it returns
true
, the function narrowsel
's type by ruling outnull
(if applicable) and intersecting with{ tagName: T }
, whereT
is the string-literal type provided as thetagName
argument. So if theel
you supply has typeHTMLElement
(orHTMLElement | null
), then ifelIs(el, 'DIV')
returnstrue
, the type ofel
will be narrowed toHTMLElement & { tagName: 'DIV' }
. -
You get autocomplete functionality and typo-prevention with the
tagName
parameter.Specifically, the
tagName
parameter must be the value of a standard DOM element'stagName
property, and this restriction further depends on the type of theel
argument you supply. For example, ifel
is an instance ofHTMLElement
, then the suppliedtagName
argument must be the value of a standard HTML element'stagName
property, like'DIV'
. Supportedel
types areHTMLElement
,SVGElement
,MathMLElement
, the more generalElement
, and unions of any of these; thetagName
argument will always be appropriately restricted. (It's best, though, ifel
is justHTMLElement
,SVGElement
, orMathMLElement
, so that you don't have to worry about confusing uppercase HTML tag-names like'A'
with lowercase SVG or MathML tag-names like'a'
.)
If you don't use elIs()
, you can just do something like if (el.matches('section'))
or if (el.tagName === 'section')
instead. But then you don't get the type-narrowing, the autocomplete, or the typo-prevention, and you'll probably make the mistake I made in the previous sentence (should be if (el.tagName === 'SECTION')
).
A few more notes:
- Because of the
tagName
restrictions, this function won't work with custom elements in TypeScript. - Although
SVGElement
is a supported type for theel
parameter, it's worth noting that, at the time of writing, every kind of SVG element has its own dedicated interface (likeSVGPathElement
), so you probably want to reach forinstanceof
with SVG tags. - Deprecated HTML elements are supported (e.g., if
el
is anHTMLElement
, thentagName
can be'MARQUEE'
).