JBrowse 2 · Linear Genome View examples

Theming & styling

Material UI themes, host page CSS and Shadow DOM.

Custom theme

Every palette option is in the theming guide.

View source — 41 lines
import {
  JBrowseLinearGenomeView,
  useCreateViewState,
} from '@jbrowse/react-linear-genome-view2'

export default function WithCustomTheme() {
  const state = useCreateViewState({
    assembly: {
      name: 'volvox',
      uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
    },
    tracks: [
      {
        trackId: 'volvox_gff3',
        name: 'Volvox genes',
        uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
      },
    ],
    view: {
      loc: 'ctgA:1105..1221',
      tracks: ['volvox-ReferenceSequenceTrack', 'volvox_gff3'],
    },
    configuration: {
      theme: {
        palette: {
          primary: { main: '#311b92' },
          secondary: { main: '#0097a7' },
          tertiary: { main: '#f57c00' },
          quaternary: { main: '#d50000' },
          bases: {
            A: { main: '#98FB98' },
            C: { main: '#87CEEB' },
            G: { main: '#DAA520' },
            T: { main: '#DC143C' },
          },
        },
      },
    },
  })
  return state ? <JBrowseLinearGenomeView viewState={state} /> : null
}

Dark theme

View source — 34 lines
import {
  JBrowseLinearGenomeView,
  useCreateViewState,
} from '@jbrowse/react-linear-genome-view2'

export default function WithDarkTheme() {
  const state = useCreateViewState({
    assembly: {
      name: 'volvox',
      uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
    },
    tracks: [
      {
        trackId: 'volvox_gff3',
        name: 'Volvox genes',
        uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
      },
    ],
    view: {
      loc: 'ctgA:1105..1221',
      tracks: ['volvox-ReferenceSequenceTrack', 'volvox_gff3'],
    },
    configuration: {
      theme: {
        palette: {
          mode: 'dark',
          primary: { main: '#333' },
          secondary: { main: '#444' },
        },
      },
    },
  })
  return state ? <JBrowseLinearGenomeView viewState={state} /> : null
}

Styling from outside the component

View source — 26 lines
import {
  JBrowseLinearGenomeView,
  useCreateViewState,
} from '@jbrowse/react-linear-genome-view2'

export default function WithOutsideStyling() {
  const state = useCreateViewState({
    assembly: {
      name: 'volvox',
      uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
    },
    tracks: [
      {
        trackId: 'volvox_gff3',
        name: 'Volvox genes',
        uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
      },
    ],
    location: 'ctgA:1105..1221',
  })
  return (
    <div style={{ textAlign: 'center', fontFamily: 'monospace' }}>
      {state ? <JBrowseLinearGenomeView viewState={state} /> : null}
    </div>
  )
}

Package as a custom element

Menus, tooltips and dialogs portal to document.body by default, outside the shadow root, where the emotion cache cannot style them. The source points the cache and each portal container inside it.

View source — 95 lines
import { createElement, useEffect, useRef, useState } from 'react'

import createCache from '@emotion/cache'
import { CacheProvider } from '@emotion/react'
import {
  JBrowseLinearGenomeView,
  useCreateViewState,
} from '@jbrowse/react-linear-genome-view2'
import r2wc from '@r2wc/react-to-web-component'
import { createPortal } from 'react-dom'

import type { EmotionCache } from '@emotion/cache'

const ShadowComponent = () => {
  const nodeRef = useRef<HTMLDivElement>(null)
  const nodeForPinRef = useRef(null)
  const [shadow, setShadow] = useState<{
    root: ShadowRoot
    cache: EmotionCache
  }>()
  useEffect(() => {
    const host = nodeRef.current
    if (host) {
      const root = host.shadowRoot ?? host.attachShadow({ mode: 'open' })
      setShadow({
        root,
        cache: createCache({
          key: 'react-shadow',
          prepend: true,
          container: root,
        }),
      })
    }
  }, [])
  const state = useCreateViewState({
    assembly: {
      name: 'volvox',
      uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
    },
    tracks: [
      {
        trackId: 'volvox_gff3',
        name: 'Volvox genes',
        uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
      },
    ],
    location: 'ctgA:1105..1221',
    configuration: {
      theme: {
        palette: { primary: { main: '#4400a6' } },
        components: {
          MuiPopover: {
            defaultProps: { container: () => nodeForPinRef.current },
          },
          MuiPopper: {
            defaultProps: { container: () => nodeForPinRef.current },
          },
          MuiTooltip: {
            defaultProps: {
              slotProps: {
                popper: { container: () => nodeForPinRef.current },
              },
            },
          },
          MuiModal: {
            defaultProps: { container: () => nodeForPinRef.current },
          },
          MuiMenu: {
            defaultProps: { container: () => nodeForPinRef.current },
          },
        },
      },
    },
  })
  return (
    <div ref={nodeRef}>
      {shadow && state
        ? createPortal(
            <CacheProvider value={shadow.cache}>
              <JBrowseLinearGenomeView viewState={state} />
              <div ref={nodeForPinRef} />
            </CacheProvider>,
            shadow.root,
          )
        : null}
    </div>
  )
}

export default function ShadowDOMOneLinearGenomeView() {
  if (customElements.get('jbrowse-linear-view') === undefined) {
    customElements.define('jbrowse-linear-view', r2wc(ShadowComponent))
  }
  return createElement('jbrowse-linear-view')
}