0.9.1 • Published 11 days ago

@expo/html-elements v0.9.1

Weekly downloads
1,883
License
MIT
Repository
github
Last release
11 days ago

Simple, light-weight, and well tested, universal semantic HTML elements as React components for iOS, Android, web, and desktop apps!

We at Expo recommend using platform agnostic primitives like View, Image, and Text whenever possible but sometimes that's not easy. Some primitives like Tables, and Footers are native to web only and currently have no way of easily accessing. This package aims to solve that while still being an optimal UI package for iOS, and Android.

What you get

  • Using @expo/html-elements will optimize your website for SEO and accessibility. Meaning your websites are indexed more accurately and your native apps better accommodate physically impaired users.
    • This package takes full advantage of react-native-web a11y rules whenever possible.
    • For example, the H1 component will render an <h1 /> on web, a UILabel on iOS, and a TextView on Android.
  • Every component can accept styles from the StyleSheet API.
  • TypeScript works for iOS, Android, and web, no more having to create monkey patches to use href on a Text element.
  • Every component is tested render tested universally for iOS, Android, and Web using the package jest-expo-enzyme. Each element is also E2E tested on iOS with Detox, and web with jest-expo-puppeteer.
  • This package is completely side-effect free!

Setup

Install:

yarn add @expo/html-elements

Import and use the package:

import { H1 } from '@expo/html-elements';

Components

Here is a list of all the currently supported elements and the web feature they map to. Not all HTML elements are supported. There are some HTML elements that mostly overlap with some universal modules, you should always try to use the universal modules whenever possible. All supported components are a capitalized variation of the semantic HTML they implement/emulate.

HTML@expo/html-elements
<a /><A />
<article /><Article />
<aside /><Aside />
<b /><B />
<blockquote /><BlockQuote />
<br /><BR />
<caption /><Caption />
<code /><Code />
<del /><Del />
<em /><EM />
<footer /><Footer />
<h1 /><H1 />
<h2 /><H2 />
<h3 /><H3 />
<h4 /><H4 />
<h5 /><H5 />
<h6 /><H6 />
<header /><Header />
<hr /><HR />
<i /><I />
<main /><Main />
<mark /><Mark />
<nav /><Nav />
<p /><P />
<pre /><Pre />
<q /><Q />
<s /><S />
<section /><Section />
<strong /><Strong />
<table /><Table />
<tbody /><TBody />
<td /><TD />
<tfoot /><TFoot />
<th /><TH />
<thead /><THead />
<time /><Time />
<tr /><TR />
<ul /><UL />
<li /><LI />
<details />⏱ Pending
<summary />⏱ Pending
<progress />⏱ Pending
<select />⏱ Pending
<picture />⏱ Pending
<figure />⏱ Pending
<figcaption />⏱ Pending
<form />⏱ Pending
<label />⏱ Pending

External

Other features not implemented in this package can be found in different parts of the Expo ecosystem.

HTMLUniversalPackage
<audio />Audioexpo-av
<button /><Button />react-native
<input type="text" /><TextInput />react-native
<input type="file" />ImagePickerexpo-image-picker
<input type="file" />DocumentPickerexpo-document-picker
<canvas /><GLView />expo-gl & Expo Canvas
<iframe /><WebView /><WebView />. @react-native-community/web-view is not maintained by Expo and doesn't have web support
<link />NoneEject the index.html with expo customize:web and link resources directly with <link />
<noscript />NoneEject the index.html with expo customize:web and use <noscript /> directly as HTML
<div /><View />react-native
<img /><Image />react-native
<span /><Text />react-native
<video /><Video />expo-av
style="backdrop-filter"<BlurView />expo-blur
style="linear-gradient()"<LinearGradient />expo-linear-gradient

Headings

Header elements will use the expected font size and margins from web universally. You can see how the native CSS units (rem, and em) are transformed in css/units.

import { H1, H2, H3, H4, H5, H6 } from '@expo/html-elements';

<H1/>

import { H1 } from '@expo/html-elements';
export default () => <H1>Example<H1/>
PlatformOutput
Web<h1 aria-level="1" dir="auto" role="heading" />
Native<Text accessibilityRole="header" style={[Custom]} />

<H2/>

import { H2 } from '@expo/html-elements';
export default () => <H2>Example<H2/>
PlatformOutput
Web<h2 aria-level="2" dir="auto" role="heading" />
Native<Text accessibilityRole="header" style={[Custom]} />

<H3/>

import { H3 } from '@expo/html-elements';
export default () => <H3>Example<H3/>
PlatformOutput
Web<h3 aria-level="3" dir="auto" role="heading" />
Native<Text accessibilityRole="header" style={[Custom]} />

<H4/>

import { H4 } from '@expo/html-elements';
export default () => <H4>Example<H4/>
PlatformOutput
Web<h4 aria-level="4" dir="auto" role="heading" />
Native<Text accessibilityRole="header" style={[Custom]} />

<H5/>

import { H5 } from '@expo/html-elements';
export default () => <H5>Example<H5/>
PlatformOutput
Web<h5 aria-level="5" dir="auto" role="heading" />
Native<Text accessibilityRole="header" style={[Custom]} />

<H6/>

import { H6 } from '@expo/html-elements';
export default () => <H6>Example<H6/>
PlatformOutput
Web<h6 aria-level="6" dir="auto" role="heading" />
Native<Text accessibilityRole="header" style={[Custom]} />

Link

<A/>

You can use the anchor element with href prop to open links. On native this will attempt to use the Linking API to open the href.

  • The CSS style is fully normalized to match <Text />
  • For pseudo-class effects like hover and focus states check out the package react-native-web-hooks | tutorial
import { A } from '@expo/html-elements';

export default () => <A href="#" target="_blank" />;
}
PlatformOutput
Web<a data-focusable="{true}" dir="auto" href="#" role="link" target="_blank" />
Native<Text accessibilityRole="link" onPress={[Function]} />

Layout

You can use layout elements like Header, Main, Footer, Section, Nav, etc. as a drop-in replacement for Views in your existing app.

Default Layout style

All layout HTML elements inherit the shared style of <View /> to accommodate the Yoga layout engine which we use on native for iOS, and Android.

  • display is always flex. This is because Yoga only implements display: flex.
  • flex-direction is always column instead of row.

Why use Layout elements

Consider the following: in your app you have a basic element at the top which wraps the buttons and title. A screen reader doesn't understand that this is a header, and mostly neither does a web crawler. But if you replace the encasing view with a <Header /> the following happens:

Some elements like Footer and Main have no iOS, or Android enhancements, but they'll still improve web. Using the proper HTML 5 elements will make your layout compliant with the HTML5 outline algorithm.

<Nav/>

import { Nav } from '@expo/html-elements';

export default () => <Nav />;
PlatformOutput
Web<nav style="display:flex" />
Native<View />

<Header/>

Renders a <header /> on web with ARIA set to banner and a View with ARIA set to header on mobile.

import { Header } from '@expo/html-elements';

export default () => <Header />;
PlatformOutput
Web<header role="banner" />
Native<View />
iOSUIView uses UIAccessibilityTraitHeader.
AndroidView will use the proper AccessibilityNodeInfoCompat.CollectionItemInfoCompat docs

<Main/>

Renders a <main /> on web with ARIA role set to main and a View with no ARIA set on mobile.

import { Main } from '@expo/html-elements';

export default () => (
    <Main>
      <P>Some content in the main element</P>
    </Main>
  );
)
PlatformOutput
Web<main role="main" style="display:flex" />
Native<View />

<Section/>

Renders a <section /> on web with ARIA set to region and a View with ARIA set to summary on mobile.

import { Section } from '@expo/html-elements';

export default () => <Section />;
PlatformOutput
Web<section role="region" style="display:flex" />
Native<View accessibilityRole="summary" />

<Article/>

Renders an <article /> on web and a View everywhere else.

import { Article } from '@expo/html-elements';

export default () => <Article />;
PlatformOutput
Web<article role="article" />
Native<View />

<Aside/>

import { Aside } from '@expo/html-elements';

export default () => <Aside />;
PlatformOutput
Web<aside role="complementary" />
Native<View />

<Footer/>

Renders an <footer /> on web and a View everywhere else.

import { Footer } from '@expo/html-elements';

export default () => <Footer />;
PlatformOutput
Web<footer role="contentinfo" />
Native<View />

Text

Text elements currently use Text universally rendering either a div or span to emulate Yoga style properly.

  • Style is modified to match web.
  • All font styles are reset (minus Code, and Pre).
  • All elements accept styles from StyleSheet API.
import { P, B, S, I, BR, Code } from '@expo/html-elements';

export default () => (
  <>
    <P>
      Hello<B>World (in bold)</B>
    </P>
    <S>strike text</S>
    <BR />
    <I>Italic</I>
    <Code>const foo = true</Code>
  </>
);

<P/>

Standard paragraph element.

PlatformOutput
Universal<Text style={{ fontSize: 14, marginVertical: '1em' }} />

<B/>

Bold text text.

PlatformOutput
Universal<Text style={{ fontWeight: 'bold' }} />

<Strong/>

Alternate bold text.

PlatformOutput
Universal<Text style={{ fontWeight: 'bold' }} />

<S/>

Strike through text.

PlatformOutput
Universal<Text style={{ textDecorationLine: 'line-through' }} />

<Del/>

Alternate strike through text.

PlatformOutput
Universal<Text style={{ textDecorationLine: 'line-through' }} />

<I/>

Italic text.

PlatformOutput
Universal<Text style={{ fontStyle: 'italic' }} />

<EM/>

Alternate italic text.

PlatformOutput
Universal<Text style={{ fontStyle: 'italic' }} />

<Code/>

Inline code block with fontFamily: 'Courier' on iOS and Web, fontFamily: 'monospace' on Android.

PlatformOutput
Universal<Text style={[Custom]} />

<Pre/>

Render a preformatted code block with fontFamily: 'Courier' on iOS and Web, fontFamily: 'monospace' on Android.

<Pre>{`
body {
  color: red;
}
`}</Pre>

// Or pass views

<Pre>
  <Code>{`const val = true`}</Code>
</Pre>
PlatformOutput
Universal<Text style={[Custom]} /> | <View />

<Mark/>

Highlight text.

PlatformOutput
Universal<Text style={{ backgroundColor: 'yellow', color: 'black' }} />

<Q/>

Quoted text.

PlatformOutput
Universal<Text style={[Custom]}>"{props.children}"</Text>

<BlockQuote/>

PlatformOutput
Universal<View style={[Custom]} />

<Time/>

  • dateTime prop is supported on web and stripped on native.
PlatformOutput
Universal<Text style={[Custom]} />

Lists

Lists can be used to create basic bulleted or numbered lists. You should try and use universal FlatList or SectionList components for long scrolling lists instead of these.

<UL/>

Create an unordered (bulleted) list <ul /> on web, and emulates the style with a <View /> on native.

  • Resets font styles everywhere.
  • Supports i18n by reversing format on iOS and Android
  • Supports custom bullets
import { UL, LI } from '@expo/html-elements';

export default () => (
  <UL>
    <LI>oranges</LI>
    <LI>apples</LI>
    <UL>
      <LI>green</LI>
      <LI>red</LI>
    </UL>
  </UL>
);
PlatformOutput
Web<ul />
Native<View style={[Custom]} />

<LI/>

Create a standard list item <li /> on web and a native view on mobile which can render text or views inside it.

PlatformOutput
Web<li />
Native<Text style={[Custom]} /> | <View style={[Custom]} />

Rules

<HR/>

Renders a <View> everywhere. Style is modified to match web.

import { HR } from '@expo/html-elements';

export default () => <HR />;
PlatformOutput
Web<hr />
Native<View style={[Custom]} />

<BR/>

Create a line break.

PlatformOutput
Web<br />
Native<View style={{height: 8, width: 0}} />

Tables

Create tables universally.

  • Each element renders to the expected type on web.
  • padding is removed from all table elements.
  • Text can only be rendered in TH and TD on mobile.
  • colSpan and rowSpan are currently web-only (PRs welcome).
import { Table, THead, TH, TBody, TFoot, TR, TD, Caption } from '@expo/html-elements';
import { Text } from 'react-native';

export default () => (
  <Table>
    <Caption>Caption</Caption>
    <THead>
      <TR>
        <TH colSpan="2">The table header</TH>
      </TR>
    </THead>
    <TBody>
      <TR>
        <TD>The table body</TD>
        <TD>with two columns</TD>
      </TR>
    </TBody>
    <TFoot>
      <TR>
        <TD>
          <Text>This is the table footer</Text>
        </TD>
      </TR>
    </TFoot>
  </Table>
);

Table example output web

<table>
  <caption>
    Caption
  </caption>
  <thead>
    <tr>
      <th colspan="2">The table header</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>The table body</td>
      <td>with two columns</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td><div>The table body</div></td>
    </tr>
  </tfoot>
</table>

<Table/>

Base element for creating a Table.

PlatformOutput
Web<table />
Native<View style={[Custom]} />

<THead/>

Header element in a Table.

PlatformOutput
Web<thead />
Native<View style={[Custom]} />

<TBody/>

Body element in a Table.

PlatformOutput
Web<tbody />
Native<View style={[Custom]} />

<TFoot/>

Footer element in a Table.

PlatformOutput
Web<tfoot />
Native<View style={[Custom]} />

<TH/>

Used to display text in the Header.

  • colSpan and rowSpan are currently web-only.
PlatformOutput
Web<th />
Native<Text style={[Custom]} />

<TR/>

Used to create a Row in a Table.

PlatformOutput
Web<tr />
Native<View style={[Custom]} />

<TD/>

Create a cell in a Table.

  • colSpan and rowSpan are currently web-only.
PlatformOutput
Web<td />
Native<View style={[Custom]} />

<Caption/>

Used to caption your table. Excepts text as a child.

PlatformOutput
Web<caption />
Native<Text style={[Custom]} />

TODO

  • Improve relative imports for better tree-shaking.

Contributing

Contributions are very welcome! Please refer to guidelines described in the contributing guide.

0.10.1

11 days ago

0.10.0

15 days ago

0.9.1

5 months ago

0.9.0

5 months ago

0.8.0

6 months ago

0.6.2

8 months ago

0.7.0

7 months ago

0.6.1

9 months ago

0.6.0

9 months ago

0.5.1

10 months ago

0.5.0

11 months ago

0.4.3

12 months ago

0.4.2

1 year ago

0.3.2

1 year ago

0.3.0

1 year ago

0.4.1

1 year ago

0.4.0

1 year ago

0.3.1

1 year ago

0.2.1

2 years ago

0.2.2

2 years ago

0.2.0

2 years ago

0.0.5

2 years ago

0.0.4

2 years ago

0.1.0

3 years ago

0.0.3

3 years ago

0.0.2

3 years ago

0.0.1

3 years ago

0.0.0

4 years ago

0.0.0-alpha.5

4 years ago

0.0.0-alpha.4

4 years ago

0.0.0-alpha.3

4 years ago

0.0.0-alpha.2

4 years ago

0.0.0-alpha.1

4 years ago