⭐️

【Polaris和訳】Components/Forms①

2021/11/06に公開

この記事について

この記事は、Polaris/Components/Formsの記事を和訳したものです。

記事内で使用する画像は、公式ドキュメント内の画像を引用して使用させていただいております。

Shopify アプリのご紹介

Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。

https://apps.shopify.com/shopify-application-314?locale=ja&from=daniel

Shopify アプリである、「らくらく日本語フォント設定|リテリア Font Picker」は、ノーコードで日本語フォントを使用できるアプリです。日本語フォントを導入することでブランドを演出することができます。

https://apps.shopify.com/font-picker-1?locale=ja&from=daniel

Forms①

Autocomplete

autocomplete コンポーネントは、マーチャントが入力すると、選択可能な候補が表示される入力フィールドです。マーチャントは、大量の選択肢の中からすばやく検索して選択することができます。オートコンプリートは、Combobox および Listbox コンポーネントの便利なラッパーですが、UI には若干の違いがあります。

Basic autocomplete

React
React
function AutocompleteExample() {
  const deselectedOptions = [
    {value: 'rustic', label: 'Rustic'},
    {value: 'antique', label: 'Antique'},
    {value: 'vinyl', label: 'Vinyl'},
    {value: 'vintage', label: 'Vintage'},
    {value: 'refurbished', label: 'Refurbished'},
  ];
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (value === '') {
        setOptions(deselectedOptions);
        return;
      }

      const filterRegex = new RegExp(value, 'i');
      const resultOptions = deselectedOptions.filter((option) =>
        option.label.match(filterRegex),
      );
      setOptions(resultOptions);
    },
    [deselectedOptions],
  );

  const updateSelection = useCallback(
    (selected) => {
      const selectedValue = selected.map((selectedItem) => {
        const matchedOption = options.find((option) => {
          return option.value.match(selectedItem);
        });
        return matchedOption && matchedOption.label;
      });

      setSelectedOptions(selected);
      setInputValue(selectedValue[0]);
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="base" />}
      placeholder="Search"
    />
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        options={options}
        selected={selectedOptions}
        onSelect={updateSelection}
        textField={textField}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 225px;">
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField6Label" for="PolarisComboboxTextField6" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField">
              <div class="Polaris-TextField__Prefix" id="PolarisComboboxTextField6Prefix"><span class="Polaris-Icon Polaris-Icon--colorBase Polaris-Icon--applyColor"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                    <path d="M8 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm9.707 4.293-4.82-4.82A5.968 5.968 0 0 0 14 8 6 6 0 0 0 2 8a6 6 0 0 0 6 6 5.968 5.968 0 0 0 3.473-1.113l4.82 4.82a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414z"></path>
                  </svg></span></div><input id="PolarisComboboxTextField6" role="combobox" placeholder="Search" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField6Label PolarisComboboxTextField6Prefix" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover6" aria-owns="Polarispopover6">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal3"></div>
  </div>
</div>

Multiple tags autocomplete

React
React
function MultiAutocompleteExample() {
  const deselectedOptions = [
    {value: 'rustic', label: 'Rustic'},
    {value: 'antique', label: 'Antique'},
    {value: 'vinyl', label: 'Vinyl'},
    {value: 'vintage', label: 'Vintage'},
    {value: 'refurbished', label: 'Refurbished'},
  ];
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (value === '') {
        setOptions(deselectedOptions);
        return;
      }

      const filterRegex = new RegExp(value, 'i');
      const resultOptions = deselectedOptions.filter((option) =>
        option.label.match(filterRegex),
      );
      let endIndex = resultOptions.length - 1;
      if (resultOptions.length === 0) {
        endIndex = 0;
      }
      setOptions(resultOptions);
    },
    [deselectedOptions],
  );

  const removeTag = useCallback(
    (tag) => () => {
      const options = [...selectedOptions];
      options.splice(options.indexOf(tag), 1);
      setSelectedOptions(options);
    },
    [selectedOptions],
  );

  const tagsMarkup = selectedOptions.map((option) => {
    let tagLabel = '';
    tagLabel = option.replace('_', ' ');
    tagLabel = titleCase(tagLabel);
    return (
      <Tag key={`option${option}`} onRemove={removeTag(option)}>
        {tagLabel}
      </Tag>
    );
  });

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      placeholder="Vintage, cotton, summer"
    />
  );

  return (
    <div style={{height: '325px'}}>
      <TextContainer>
        <Stack>{tagsMarkup}</Stack>
      </TextContainer>
      <br />
      <Autocomplete
        allowMultiple
        options={options}
        selected={selectedOptions}
        textField={textField}
        onSelect={setSelectedOptions}
        listTitle="Suggested Tags"
      />
    </div>
  );

  function titleCase(string) {
    return string
      .toLowerCase()
      .split(' ')
      .map((word) => word.replace(word[0], word[0].toUpperCase()))
      .join('');
  }
}
HTML
HTML
<div>
  <div style="height: 325px;">
    <div class="Polaris-TextContainer">
      <div class="Polaris-Stack"></div>
    </div><br>
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField8Label" for="PolarisComboboxTextField8" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField"><input id="PolarisComboboxTextField8" role="combobox" placeholder="Vintage, cotton, summer" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField8Label" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover8" aria-owns="Polarispopover8">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal4"></div>
  </div>
</div>

Multiple sections autocomplete

React
React
function AutocompleteExample() {
  const deselectedOptions = useMemo(
    () => [
      {
        title: 'Frequently used',
        options: [
          {value: 'ups', label: 'UPS'},
          {value: 'usps', label: 'USPS'},
        ],
      },
      {
        title: 'All carriers',
        options: [
          {value: 'dhl', label: 'DHL Express'},
          {value: 'canada_post', label: 'Canada Post'},
        ],
      },
    ],
    [],
  );
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (value === '') {
        setOptions(deselectedOptions);
        return;
      }

      const filterRegex = new RegExp(value, 'i');
      const resultOptions = [];

      deselectedOptions.forEach((opt) => {
        const lol = opt.options.filter((option) =>
          option.label.match(filterRegex),
        );

        resultOptions.push({
          title: opt.title,
          options: lol,
        });
      });

      setOptions(resultOptions);
    },
    [deselectedOptions],
  );

  const updateSelection = useCallback(
    ([selected]) => {
      let selectedValue;

      options.forEach(({options: opt}) => {
        if (selectedValue) {
          return;
        }

        const matchedOption = opt.find((option) =>
          option.value.match(selected),
        );

        if (matchedOption) {
          selectedValue = matchedOption.label;
        }
      });

      setSelectedOptions([selected]);
      setInputValue(String(selectedValue) ? String(selectedValue) : '');
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="base" />}
      placeholder="Search"
    />
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        textField={textField}
        selected={selectedOptions}
        options={options}
        onSelect={updateSelection}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 225px;">
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField10Label" for="PolarisComboboxTextField10" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField">
              <div class="Polaris-TextField__Prefix" id="PolarisComboboxTextField10Prefix"><span class="Polaris-Icon Polaris-Icon--colorBase Polaris-Icon--applyColor"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                    <path d="M8 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm9.707 4.293-4.82-4.82A5.968 5.968 0 0 0 14 8 6 6 0 0 0 2 8a6 6 0 0 0 6 6 5.968 5.968 0 0 0 3.473-1.113l4.82 4.82a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414z"></path>
                  </svg></span></div><input id="PolarisComboboxTextField10" role="combobox" placeholder="Search" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField10Label PolarisComboboxTextField10Prefix" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover10" aria-owns="Polarispopover10">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal5"></div>
  </div>
</div>

Autocomplete with loading

React
React
function AutocompleteExample() {
  const deselectedOptions = [
    {value: 'rustic', label: 'Rustic'},
    {value: 'antique', label: 'Antique'},
    {value: 'vinyl', label: 'Vinyl'},
    {value: 'vintage', label: 'Vintage'},
    {value: 'refurbished', label: 'Refurbished'},
  ];
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);
  const [loading, setLoading] = useState(false);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (!loading) {
        setLoading(true);
      }

      setTimeout(() => {
        if (value === '') {
          setOptions(deselectedOptions);
          setLoading(false);
          return;
        }
        const filterRegex = new RegExp(value, 'i');
        const resultOptions = deselectedOptions.filter((option) =>
          option.label.match(filterRegex),
        );
        setOptions(resultOptions);
        setLoading(false);
      }, 300);
    },
    [deselectedOptions, options, loading],
  );

  const updateSelection = useCallback(
    (selected) => {
      const selectedText = selected.map((selectedItem) => {
        const matchedOption = options.find((option) => {
          return option.value.match(selectedItem);
        });
        return matchedOption && matchedOption.label;
      });
      setSelectedOptions(selected);
      setInputValue(selectedText[0]);
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="base" />}
      placeholder="Search"
    />
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        options={options}
        selected={selectedOptions}
        onSelect={updateSelection}
        loading={loading}
        textField={textField}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 225px;">
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField12Label" for="PolarisComboboxTextField12" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField">
              <div class="Polaris-TextField__Prefix" id="PolarisComboboxTextField12Prefix"><span class="Polaris-Icon Polaris-Icon--colorBase Polaris-Icon--applyColor"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                    <path d="M8 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm9.707 4.293-4.82-4.82A5.968 5.968 0 0 0 14 8 6 6 0 0 0 2 8a6 6 0 0 0 6 6 5.968 5.968 0 0 0 3.473-1.113l4.82 4.82a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414z"></path>
                  </svg></span></div><input id="PolarisComboboxTextField12" role="combobox" placeholder="Search" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField12Label PolarisComboboxTextField12Prefix" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover12" aria-owns="Polarispopover12">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal6"></div>
  </div>
</div>

Autocomplete with lazy loading

React
React
function AutoCompleteLazyLoadExample() {
  const paginationInterval = 25;
  const deselectedOptions = Array.from(Array(100)).map((_, index) => ({
    value: `rustic ${index + 1}`,
    label: `Rustic ${index + 1}`,
  }));

  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);
  const [isLoading, setIsLoading] = useState(false);
  const [willLoadMoreResults, setWillLoadMoreResults] = useState(true);
  const [visibleOptionIndex, setVisibleOptionIndex] =
    useState(paginationInterval);

  const handleLoadMoreResults = useCallback(() => {
    if (willLoadMoreResults) {
      setIsLoading(true);

      setTimeout(() => {
        const remainingOptionCount = options.length - visibleOptionIndex;
        const nextVisibleOptionIndex =
          remainingOptionCount >= paginationInterval
            ? visibleOptionIndex + paginationInterval
            : visibleOptionIndex + remainingOptionCount;

        setIsLoading(false);
        setVisibleOptionIndex(nextVisibleOptionIndex);

        if (remainingOptionCount <= paginationInterval) {
          setWillLoadMoreResults(false);
        }
      }, 1000);
    }
  }, [willLoadMoreResults, visibleOptionIndex, options.length]);

  const removeTag = useCallback(
    (tag) => () => {
      const options = [...selectedOptions];
      options.splice(options.indexOf(tag), 1);
      setSelectedOptions(options);
    },
    [selectedOptions],
  );

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (value === '') {
        setOptions(deselectedOptions);
        return;
      }

      const filterRegex = new RegExp(value, 'i');
      const resultOptions = deselectedOptions.filter((option) =>
        option.label.match(filterRegex),
      );

      let endIndex = resultOptions.length - 1;
      if (resultOptions.length === 0) {
        endIndex = 0;
      }
      setOptions(resultOptions);
      setInputValue;
    },
    [deselectedOptions, options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      placeholder="Vintage, cotton, summer"
    />
  );

  const hasSelectedOptions = selectedOptions.length > 0;

  const tagsMarkup = hasSelectedOptions
    ? selectedOptions.map((option) => {
        let tagLabel = '';
        tagLabel = option.replace('_', ' ');
        tagLabel = titleCase(tagLabel);
        return (
          <Tag key={`option${option}`} onRemove={removeTag(option)}>
            {tagLabel}
          </Tag>
        );
      })
    : null;
  const optionList = options.slice(0, visibleOptionIndex);
  const selectedTagMarkup = hasSelectedOptions ? (
    <Stack spacing="extraTight">{tagsMarkup}</Stack>
  ) : null;

  return (
    <Stack vertical>
      {selectedTagMarkup}
      <Autocomplete
        allowMultiple
        options={optionList}
        selected={selectedOptions}
        textField={textField}
        onSelect={setSelectedOptions}
        listTitle="Suggested Tags"
        loading={isLoading}
        onLoadMoreResults={handleLoadMoreResults}
        willLoadMoreResults={willLoadMoreResults}
      />
    </Stack>
  );

  function titleCase(string) {
    return string
      .toLowerCase()
      .split(' ')
      .map((word) => {
        return word.replace(word[0], word[0].toUpperCase());
      })
      .join(' ');
  }
}
HTML
HTML
<div>
  <div class="Polaris-Stack Polaris-Stack--vertical">
    <div class="Polaris-Stack__Item">
      <div>
        <div class="">
          <div class="Polaris-Labelled__LabelWrapper">
            <div class="Polaris-Label"><label id="PolarisComboboxTextField14Label" for="PolarisComboboxTextField14" class="Polaris-Label__Text">Tags</label></div>
          </div>
          <div class="Polaris-Connected">
            <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
              <div class="Polaris-TextField"><input id="PolarisComboboxTextField14" role="combobox" placeholder="Vintage, cotton, summer" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField14Label" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover14" aria-owns="Polarispopover14">
                <div class="Polaris-TextField__Backdrop"></div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal7"></div>
  </div>
</div>

Autocomplete with empty state

React
React
function AutocompleteExample() {
  const deselectedOptions = [
    {value: 'rustic', label: 'Rustic'},
    {value: 'antique', label: 'Antique'},
    {value: 'vinyl', label: 'Vinyl'},
    {value: 'vintage', label: 'Vintage'},
    {value: 'refurbished', label: 'Refurbished'},
  ];
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);
  const [loading, setLoading] = useState(false);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (!loading) {
        setLoading(true);
      }

      setTimeout(() => {
        if (value === '') {
          setOptions(deselectedOptions);
          setLoading(false);
          return;
        }
        const filterRegex = new RegExp(value, 'i');
        const resultOptions = deselectedOptions.filter((option) =>
          option.label.match(filterRegex),
        );
        setOptions(resultOptions);
        setLoading(false);
      }, 300);
    },
    [deselectedOptions, loading, options],
  );

  const updateSelection = useCallback(
    (selected) => {
      const selectedText = selected.map((selectedItem) => {
        const matchedOption = options.find((option) => {
          return option.value.match(selectedItem);
        });
        return matchedOption && matchedOption.label;
      });
      setSelectedOptions(selected);
      setInputValue(selectedText[0]);
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="base" />}
      placeholder="Search"
    />
  );

  const emptyState = (
    <React.Fragment>
      <Icon source={SearchMinor} />
      <div style={{textAlign: 'center'}}>
        <TextContainer>Could not find any results</TextContainer>
      </div>
    </React.Fragment>
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        options={options}
        selected={selectedOptions}
        onSelect={updateSelection}
        emptyState={emptyState}
        loading={loading}
        textField={textField}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 225px;">
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField16Label" for="PolarisComboboxTextField16" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField">
              <div class="Polaris-TextField__Prefix" id="PolarisComboboxTextField16Prefix"><span class="Polaris-Icon Polaris-Icon--colorBase Polaris-Icon--applyColor"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                    <path d="M8 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm9.707 4.293-4.82-4.82A5.968 5.968 0 0 0 14 8 6 6 0 0 0 2 8a6 6 0 0 0 6 6 5.968 5.968 0 0 0 3.473-1.113l4.82 4.82a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414z"></path>
                  </svg></span></div><input id="PolarisComboboxTextField16" role="combobox" placeholder="Search" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField16Label PolarisComboboxTextField16Prefix" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover16" aria-owns="Polarispopover16">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal8"></div>
  </div>
</div>

Autocomplete with action

React
React
function AutocompleteActionBeforeExample() {
  const deselectedOptions = [
    {value: 'rustic', label: 'Rustic'},
    {value: 'antique', label: 'Antique'},
    {value: 'vinyl', label: 'Vinyl'},
    {value: 'vintage', label: 'Vintage'},
    {value: 'refurbished', label: 'Refurbished'},
  ];
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);
  const [loading, setLoading] = useState(false);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (!loading) {
        setLoading(true);
      }

      setTimeout(() => {
        if (value === '') {
          setOptions(deselectedOptions);
          setLoading(false);
          return;
        }
        const filterRegex = new RegExp(value, 'i');
        const resultOptions = options.filter((option) =>
          option.label.match(filterRegex),
        );
        setOptions(resultOptions);
        setLoading(false);
      }, 300);
    },
    [deselectedOptions, loading, options],
  );

  const updateSelection = useCallback(
    (selected) => {
      const selectedText = selected.map((selectedItem) => {
        const matchedOption = options.find((option) => {
          return option.value.match(selectedItem);
        });
        return matchedOption && matchedOption.label;
      });
      setSelectedOptions(selected);
      setInputValue(selectedText[0]);
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="inkLighter" />}
      placeholder="Search"
    />
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        actionBefore={{
          accessibilityLabel: 'Action label',
          badge: {
            status: 'new',
            content: 'New!',
          },
          content: 'Action with long name',
          ellipsis: true,
          helpText: 'Help text',
          icon: CirclePlusMinor,
        }}
        options={options}
        selected={selectedOptions}
        onSelect={updateSelection}
        listTitle="Suggested tags"
        loading={loading}
        textField={textField}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 225px;">
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField18Label" for="PolarisComboboxTextField18" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField">
              <div class="Polaris-TextField__Prefix" id="PolarisComboboxTextField18Prefix"><span class="Polaris-Icon Polaris-Icon--applyColor"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                    <path d="M8 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm9.707 4.293-4.82-4.82A5.968 5.968 0 0 0 14 8 6 6 0 0 0 2 8a6 6 0 0 0 6 6 5.968 5.968 0 0 0 3.473-1.113l4.82 4.82a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414z"></path>
                  </svg></span></div><input id="PolarisComboboxTextField18" role="combobox" placeholder="Search" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField18Label PolarisComboboxTextField18Prefix" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover18" aria-owns="Polarispopover18">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal9"></div>
  </div>
</div>

Autocomplete with wrapping action

React
React
function AutocompleteActionBeforeExample() {
  const deselectedOptions = [
    {value: 'rustic', label: 'Rustic'},
    {value: 'antique', label: 'Antique'},
    {value: 'vinyl', label: 'Vinyl'},
    {value: 'vintage', label: 'Vintage'},
    {value: 'refurbished', label: 'Refurbished'},
  ];
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);
  const [loading, setLoading] = useState(false);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (!loading) {
        setLoading(true);
      }

      setTimeout(() => {
        if (value === '') {
          setOptions(deselectedOptions);
          setLoading(false);
          return;
        }
        const filterRegex = new RegExp(value, 'i');
        const resultOptions = options.filter((option) =>
          option.label.match(filterRegex),
        );
        setOptions(resultOptions);
        setLoading(false);
      }, 300);
    },
    [deselectedOptions, loading, options],
  );

  const updateSelection = useCallback(
    (selected) => {
      const selectedText = selected.map((selectedItem) => {
        const matchedOption = options.find((option) => {
          return option.value.match(selectedItem);
        });
        return matchedOption && matchedOption.label;
      });
      setSelectedOptions(selected);
      setInputValue(selectedText[0]);
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="inkLighter" />}
      placeholder="Search"
    />
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        actionBefore={{
          accessibilityLabel: 'Action label',
          badge: {
            status: 'new',
            content: 'New!',
          },
          content:
            'Action with long name that will need to wrap on small display in order to have a nice display',
          ellipsis: true,
          helpText: 'Help text',
          icon: CirclePlusMinor,
          wrapOverflow: true,
        }}
        options={options}
        selected={selectedOptions}
        onSelect={updateSelection}
        listTitle="Suggested tags"
        loading={loading}
        textField={textField}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 225px;">
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField20Label" for="PolarisComboboxTextField20" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField">
              <div class="Polaris-TextField__Prefix" id="PolarisComboboxTextField20Prefix"><span class="Polaris-Icon Polaris-Icon--applyColor"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                    <path d="M8 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm9.707 4.293-4.82-4.82A5.968 5.968 0 0 0 14 8 6 6 0 0 0 2 8a6 6 0 0 0 6 6 5.968 5.968 0 0 0 3.473-1.113l4.82 4.82a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414z"></path>
                  </svg></span></div><input id="PolarisComboboxTextField20" role="combobox" placeholder="Search" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField20Label PolarisComboboxTextField20Prefix" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover20" aria-owns="Polarispopover20">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal10"></div>
  </div>
</div>

Autocomplete with destructive action

React
React
function AutocompleteActionBeforeExample() {
  const deselectedOptions = [
    {value: 'rustic', label: 'Rustic'},
    {value: 'antique', label: 'Antique'},
    {value: 'vinyl', label: 'Vinyl'},
    {value: 'vintage', label: 'Vintage'},
    {value: 'refurbished', label: 'Refurbished'},
  ];
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);
  const [loading, setLoading] = useState(false);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (!loading) {
        setLoading(true);
      }

      setTimeout(() => {
        if (value === '') {
          setOptions(deselectedOptions);
          setLoading(false);
          return;
        }
        const filterRegex = new RegExp(value, 'i');
        const resultOptions = options.filter((option) =>
          option.label.match(filterRegex),
        );
        setOptions(resultOptions);
        setLoading(false);
      }, 300);
    },
    [deselectedOptions, loading, options],
  );

  const updateSelection = useCallback(
    (selected) => {
      const selectedText = selected.map((selectedItem) => {
        const matchedOption = options.find((option) => {
          return option.value.match(selectedItem);
        });
        return matchedOption && matchedOption.label;
      });
      setSelectedOptions(selected);
      setInputValue(selectedText[0]);
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="inkLighter" />}
      placeholder="Search"
    />
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        actionBefore={{
          accessibilityLabel: 'Destructive action label',
          content: 'Destructive action',
          destructive: true,
          icon: DeleteMinor,
        }}
        options={options}
        selected={selectedOptions}
        onSelect={updateSelection}
        listTitle="Suggested tags"
        loading={loading}
        textField={textField}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 225px;">
    <div>
      <div class="">
        <div class="Polaris-Labelled__LabelWrapper">
          <div class="Polaris-Label"><label id="PolarisComboboxTextField22Label" for="PolarisComboboxTextField22" class="Polaris-Label__Text">Tags</label></div>
        </div>
        <div class="Polaris-Connected">
          <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
            <div class="Polaris-TextField">
              <div class="Polaris-TextField__Prefix" id="PolarisComboboxTextField22Prefix"><span class="Polaris-Icon Polaris-Icon--applyColor"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                    <path d="M8 12a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm9.707 4.293-4.82-4.82A5.968 5.968 0 0 0 14 8 6 6 0 0 0 2 8a6 6 0 0 0 6 6 5.968 5.968 0 0 0 3.473-1.113l4.82 4.82a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414z"></path>
                  </svg></span></div><input id="PolarisComboboxTextField22" role="combobox" placeholder="Search" class="Polaris-TextField__Input" aria-labelledby="PolarisComboboxTextField22Label PolarisComboboxTextField22Prefix" aria-invalid="false" aria-autocomplete="list" aria-expanded="false" value="" tabindex="0" aria-controls="Polarispopover22" aria-owns="Polarispopover22">
              <div class="Polaris-TextField__Backdrop"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer">
    <div data-portal-id="popover-Polarisportal11"></div>
  </div>
</div>

Props

allowMultiple
boolean
複数のオプションを選択可能

emptyState
React.ReactNode
選択肢がない場合にレンダリングされます

id
string
オートコンプリートの一意の識別子

listTitle
string
選択肢のリストのタイトル

loading
boolean
ディスプレイローディングの state

options (Required)
Array
リストアップされるオプションのコレクション

preferredPosition
"above" | "below" | "mostSpace"
ポップオーバーを開くのに適した方向

selected(Required)
string[]
選択されたオプション

textField (Required)
ReactElement
選択肢のリストに添付されるテキストフィールドコンポーネント

willLoadMoreResults
boolean
より多くの結果を動的に読み込むかどうかを示す

onLoadMoreResults
() => void
リストの最後に到達したときのコールバック

onSelect (Required)
(selected: string[]) => void
選択肢が変更されたときのコールバック

アクセシビリティ

構造

オートコンプリートコンポーネントは、ARIA 1.2 combobox patternAria 1.2 Listbox patternに基づいています。

autocomplete リストは、デフォルトでは、テキストフィールドなどのコントロールの下に表示されるので、マーチャントが見つけやすく、使いやすいです。ただし、preferredPositionプロップで位置を変更できます。

autocomplete 機能は、視覚障害、運動障害、認知障害を持つマーチャントにとって難しい場合があります。ベストプラクティスに基づいて構築されていても、一部の支援技術ではこれらの機能を使用することが困難な場合があります。マーチャントは、autocomplete に頼らずに、常に検索、データ入力、またはその他のアクティビティを実行できる必要があります。

キーボード対応

  • tabキーで autocomplete のテキスト入力にキーボードフォーカスを与える(逆方向にタブするときは shift+tab キー)。
  • 上下の矢印キーでオプションのリストにアクセス
  • フォーカスされているオプションを enter/return キーで選択

ベストプラクティス

autocomplete コンポーネントは、以下の点に注意してください。

  • マーチャントがどのような種類のオプションを利用できるかがわかるように、明確なラベルを付ける。
  • 一度に表示するオプションの数を制限する。
  • ポップオーバーの中では使用しない。
  • オプションのデータが入力されている間は、マーチャントに読み込み中であることを示す。

コンテンツガイドライン

autocomplete 用の入力フィールドは、テキストフィールドのコンテンツガイドラインに従うべきです。

関連コンポーネント

Checkbox

チェックボックスは、マーチャントがさまざまな選択(0、1、または複数)をするための手段として最も一般的に使用されます。また、マーチャントが特定の条件やサービスに同意することを示す手段としても使用されます。

Web

Default checkboxes

フォームで、何かの状態をオンまたはオフに切り替えるために使用します。デフォルトのチェックボックスは、「選択されているが無効」「選択されていない」の 2 つの状態で表示されます。

React
React
function CheckboxExample() {
  const [checked, setChecked] = useState(false);
  const handleChange = useCallback((newChecked) => setChecked(newChecked), []);

  return (
    <Checkbox
      label="Basic checkbox"
      checked={checked}
      onChange={handleChange}
    />
  );
}
HTML
HTML
<div><label class="Polaris-Choice" for="PolarisCheckbox2"><span class="Polaris-Choice__Control"><span class="Polaris-Checkbox"><input id="PolarisCheckbox2" type="checkbox" class="Polaris-Checkbox__Input" aria-invalid="false" role="checkbox" aria-checked="false" value=""><span class="Polaris-Checkbox__Backdrop"></span><span class="Polaris-Checkbox__Icon"><span class="Polaris-Icon"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
              <path d="m8.315 13.859-3.182-3.417a.506.506 0 0 1 0-.684l.643-.683a.437.437 0 0 1 .642 0l2.22 2.393 4.942-5.327a.436.436 0 0 1 .643 0l.643.684a.504.504 0 0 1 0 .683l-5.91 6.35a.437.437 0 0 1-.642 0"></path>
            </svg></span></span></span></span><span class="Polaris-Choice__Label">Basic checkbox</span></label>
  <div id="PolarisPortalsContainer"></div>
</div>

Props

ariaControls
string
チェックボックスで制御される要素の ID を示す

ariaDescribedBy
string
チェックボックスを記述した要素の ID を示す

checked
boolean | "indeterminate"
チェックボックスが選択されています。indeterminateでは、チェックボックスに横線が表示されます。

disabled
boolean
入力を無効にする

error
string | ReactElement | (string | ReactElement)[] | boolean
エラーメッセージを表示する

helpText
React.ReactNode
使用時の補助テキストの追加

id
string
フォーム入力用の ID

label(Required)
React.ReactNode
チェックボックスのラベル

labelHidden
boolean
ラベルを視覚的に隠す

name
string
フォーム入力用の名前

value
string
フォーム入力用の値

onBlur
() => void
フォーカスが外れた時のコールバック

onChange
(newChecked: boolean, id: string) => void
チェックボックスが切り替えられた時のコールバック

onFocus
() => void
チェックボックスがフォーカスされた時のコールバック

アクセシビリティ

スクリーン・リーダーはチェックボックスの状態を自動的に伝えます。

  • disabledprop を使って、チェックボックスの<input>に HTML のdisabled属性を適用します。これにより、マーチャントはチェックボックスを操作することができなくなり、アシスティブテクノロジーにはその非アクティブな状態が伝えられます。
  • idprop を使って、チェックボックスに一意のid属性値を与えます。idが指定されていない場合は、コンポーネントがidを生成します。アシスティブテクノロジーで正しく動作させるためには、すべてのチェックボックスに一意のid値が必要です。
  • checked="indeterminate"を設定すると、aria-checked="mixed"を使用して、チェックボックスの状態を伝えます。
  • ariaControlsprop を設定すると、チェックボックスの内容や存在が制御される要素の ID が、aria-controls属性を使ってスクリーン・リーダーのユーザーに伝えられます。

ラベリング

  • 必須のlabelprop は、すべてのマーチャントにチェックボックスの目的を伝えます。
  • labelHiddenprop を使ってラベルを視覚的に隠しますが、支援技術で利用できるようにします。
  • helpTextprop でヘルプテキストを与えたり、errorprop でインラインエラーメッセージを与える場合、ヘルプやエラーの内容はaria-describedby属性でスクリーンリーダーのユーザーに伝えられます。

キーボードサポート

  • 各チェックボックスにフォーカスを移すには、tabキー(逆方向のタブ操作の場合は、shift+tabキー)を使います。
  • キーボードフォーカスがある状態でチェックボックスを操作するには、sapceキー
Android

デフォルトのチェックボックス

フォームで、何かの状態をオンまたはオフに切り替えるために使用します。デフォルトのチェックボックスは、「選択されているが無効」「選択されていない」の 2 つの状態で表示されます。

アクセシビリティ

Android のアクセシビリティについては、Material Design と開発ドキュメントをご覧ください。

iOS

デフォルトのチェックボックス

フォームで、何かの状態をオンまたはオフに切り替えるために使用します。デフォルトのチェックボックスは、「選択されているが無効」「選択されていない」の 2 つの状態で表示されます。

アクセシビリティ

iOS のアクセシビリティについては、Apple の Human Interface Guidelines や API のドキュメントをご覧ください。

ベストプラクティス

チェックボックスは以下のことに注意してください。

  • あるチェックボックスを選択しても、リスト内の別のチェックボックスの選択状態が変わることはありません。ただし、複数の項目を一括して選択するためにチェックボックスを使用する場合は例外です。
  • ポジティブなフレームであること:例えば、Turn off notificationsではなくTurn on notificationsのように。
  • 設定のオン/オフを切り替えるために使用される場合は、必ずラベルを付ける。
  • アルファベット順、数字順、時間順、その他の明確なシステムなど、論理的な順序に沿って表示されていること。
  • 必要に応じて、詳細情報へのリンクやサブタイトルをつけて、より詳しい説明をすること。チェックボックスの説明をツールチップに頼るのはやめましょう。

コンテンツガイドライン

チェックボックスのリスト

チェックボックスを使うリストは以下のことに注意してください。

  • 最初の文字を大文字にする。

  • カンマやセミコロンを各行の最後に使わない。

  • チェックボックスでマーチャントに規約やサービスへの同意を求めている稀なケースでは、一人称である。

関連コンポーネント

Choice list

チョイスリストでは、グループ化されたラジオボタンやチェックボックスのリストを作成できます。このコンポーネントは、インタラクティブな選択肢の関連リストをグループ化する必要がある場合に使用します。

Web

Single choice list

マーチャントがリストから 1 つのオプションを選択できるようにします。

  • すべてのオプションが、どちらか一方のみの選択であることを確認してください。

React
React
function SingleChoiceListExample() {
  const [selected, setSelected] = useState(['hidden']);

  const handleChange = useCallback((value) => setSelected(value), []);

  return (
    <ChoiceList
      title="Company name"
      choices={[
        {label: 'Hidden', value: 'hidden'},
        {label: 'Optional', value: 'optional'},
        {label: 'Required', value: 'required'},
      ]}
      selected={selected}
      onChange={handleChange}
    />
  );
}
HTML
HTML
<div>
  <fieldset class="Polaris-ChoiceList" id="PolarisChoiceList2" aria-invalid="false">
    <legend class="Polaris-ChoiceList__Title">Company name</legend>
    <ul class="Polaris-ChoiceList__Choices">
      <li><label class="Polaris-Choice" for="PolarisRadioButton4"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton4" name="PolarisChoiceList2" type="radio" class="Polaris-RadioButton__Input" value="hidden" checked=""><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Hidden</span></label></li>
      <li><label class="Polaris-Choice" for="PolarisRadioButton5"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton5" name="PolarisChoiceList2" type="radio" class="Polaris-RadioButton__Input" value="optional"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Optional</span></label></li>
      <li><label class="Polaris-Choice" for="PolarisRadioButton6"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton6" name="PolarisChoiceList2" type="radio" class="Polaris-RadioButton__Input" value="required"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Required</span></label></li>
    </ul>
  </fieldset>
  <div id="PolarisPortalsContainer"></div>
</div>

Single choice list with error

エラーメッセージとエラーのあるフィールドを結びつけることで、アクセス可能なエラー処理を可能にします。

React
React
function ChoiceListWithErrorExample() {
  const [selected, setSelected] = useState('hidden');

  const handleChange = useCallback((value) => setSelected(value), []);

  return (
    <ChoiceList
      title="Company name"
      choices={[
        {label: 'Hidden', value: 'hidden', describedByError: true},
        {label: 'Optional', value: 'optional'},
        {label: 'Required', value: 'required'},
      ]}
      selected={selected}
      onChange={handleChange}
      error="Company name cannot be hidden at this time"
    />
  );
}
HTML
html
<div>
  <fieldset class="Polaris-ChoiceList" id="PolarisChoiceList4" aria-invalid="true">
    <legend class="Polaris-ChoiceList__Title">Company name</legend>
    <ul class="Polaris-ChoiceList__Choices">
      <li><label class="Polaris-Choice" for="PolarisRadioButton10"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton10" name="PolarisChoiceList4" type="radio" class="Polaris-RadioButton__Input" aria-describedby="PolarisChoiceList4Error" value="hidden" checked=""><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Hidden</span></label></li>
      <li><label class="Polaris-Choice" for="PolarisRadioButton11"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton11" name="PolarisChoiceList4" type="radio" class="Polaris-RadioButton__Input" value="optional"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Optional</span></label></li>
      <li><label class="Polaris-Choice" for="PolarisRadioButton12"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton12" name="PolarisChoiceList4" type="radio" class="Polaris-RadioButton__Input" value="required"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Required</span></label></li>
    </ul>
    <div class="Polaris-ChoiceList__ChoiceError">
      <div id="PolarisChoiceList4Error" class="Polaris-InlineError">
        <div class="Polaris-InlineError__Icon"><span class="Polaris-Icon"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
              <path d="M10 18a8 8 0 1 1 0-16 8 8 0 0 1 0 16zM9 9a1 1 0 0 0 2 0V7a1 1 0 1 0-2 0v2zm0 4a1 1 0 1 0 2 0 1 1 0 0 0-2 0z"></path>
            </svg></span></div>Company name cannot be hidden at this time
      </div>
    </div>
  </fieldset>
  <div id="PolarisPortalsContainer"></div>
</div>

Multi-choice list

マーチャントがリストから複数のオプションを選択できるようにします。

  • どちらか一方しか選べないオプションは避けてください。

React
React
function MultiChoiceListExample() {
  const [selected, setSelected] = useState(['hidden']);

  const handleChange = useCallback((value) => setSelected(value), []);

  return (
    <ChoiceList
      allowMultiple
      title="While the customer is checking out"
      choices={[
        {
          label: 'Use the shipping address as the billing address by default',
          value: 'shipping',
          helpText:
            'Reduces the number of fields required to check out. The billing address can still be edited.',
        },
        {
          label: 'Require a confirmation step',
          value: 'confirmation',
          helpText:
            'Customers must review their order details before purchasing.',
        },
      ]}
      selected={selected}
      onChange={handleChange}
    />
  );
}
HTML
HTML
<div>
  <fieldset class="Polaris-ChoiceList" id="PolarisChoiceList6[]" aria-invalid="false">
    <legend class="Polaris-ChoiceList__Title">While the customer is checking out</legend>
    <ul class="Polaris-ChoiceList__Choices">
      <li>
        <div><label class="Polaris-Choice" for="PolarisCheckbox3"><span class="Polaris-Choice__Control"><span class="Polaris-Checkbox"><input id="PolarisCheckbox3" name="PolarisChoiceList6[]" type="checkbox" class="Polaris-Checkbox__Input" aria-invalid="false" aria-describedby="PolarisCheckbox3HelpText" role="checkbox" aria-checked="false" value="shipping"><span class="Polaris-Checkbox__Backdrop"></span><span class="Polaris-Checkbox__Icon"><span class="Polaris-Icon"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                      <path d="m8.315 13.859-3.182-3.417a.506.506 0 0 1 0-.684l.643-.683a.437.437 0 0 1 .642 0l2.22 2.393 4.942-5.327a.436.436 0 0 1 .643 0l.643.684a.504.504 0 0 1 0 .683l-5.91 6.35a.437.437 0 0 1-.642 0"></path>
                    </svg></span></span></span></span><span class="Polaris-Choice__Label">Use the shipping address as the billing address by default</span></label>
          <div class="Polaris-Choice__Descriptions">
            <div class="Polaris-Choice__HelpText" id="PolarisCheckbox3HelpText">Reduces the number of fields required to check out. The billing address can still be edited.</div>
          </div>
        </div>
      </li>
      <li>
        <div><label class="Polaris-Choice" for="PolarisCheckbox4"><span class="Polaris-Choice__Control"><span class="Polaris-Checkbox"><input id="PolarisCheckbox4" name="PolarisChoiceList6[]" type="checkbox" class="Polaris-Checkbox__Input" aria-invalid="false" aria-describedby="PolarisCheckbox4HelpText" role="checkbox" aria-checked="false" value="confirmation"><span class="Polaris-Checkbox__Backdrop"></span><span class="Polaris-Checkbox__Icon"><span class="Polaris-Icon"><span class="Polaris-VisuallyHidden"></span><svg viewBox="0 0 20 20" class="Polaris-Icon__Svg" focusable="false" aria-hidden="true">
                      <path d="m8.315 13.859-3.182-3.417a.506.506 0 0 1 0-.684l.643-.683a.437.437 0 0 1 .642 0l2.22 2.393 4.942-5.327a.436.436 0 0 1 .643 0l.643.684a.504.504 0 0 1 0 .683l-5.91 6.35a.437.437 0 0 1-.642 0"></path>
                    </svg></span></span></span></span><span class="Polaris-Choice__Label">Require a confirmation step</span></label>
          <div class="Polaris-Choice__Descriptions">
            <div class="Polaris-Choice__HelpText" id="PolarisCheckbox4HelpText">Customers must review their order details before purchasing.</div>
          </div>
        </div>
      </li>
    </ul>
  </fieldset>
  <div id="PolarisPortalsContainer"></div>
</div>

Single-choice or multi-choice list with children content (always rendered)

マーチャントが選択肢の下にある追加コンテンツを見たり、操作したりする必要がある場合に使用します。コンテンツは常にレンダリングされます。選択肢が一つしかないときと複数あるときの両方に対応しています。

React
React
function SingleOrMultiChoiceListWithChildrenContextExample() {
  const [selected, setSelected] = useState(['none']);
  const [textFieldValue, setTextFieldValue] = useState('');

  const handleChoiceListChange = useCallback((value) => setSelected(value), []);

  const handleTextFieldChange = useCallback(
    (value) => setTextFieldValue(value),
    [],
  );

  const renderChildren = useCallback(
    () => (
      <TextField
        label="Minimum Quantity"
        labelHidden
        onChange={handleTextFieldChange}
        value={textFieldValue}
        autoComplete="off"
      />
    ),
    [handleTextFieldChange, textFieldValue],
  );

  return (
    <ChoiceList
      title="Discount minimum requirements"
      choices={[
        {label: 'None', value: 'none'},
        {label: 'Minimum purchase', value: 'minimum_purchase'},
        {
          label: 'Minimum quantity',
          value: 'minimum_quantity',
          renderChildren,
        },
      ]}
      selected={selected}
      onChange={handleChoiceListChange}
    />
  );
}
HTML
HTML
<div>
  <fieldset class="Polaris-ChoiceList" id="PolarisChoiceList8" aria-invalid="false">
    <legend class="Polaris-ChoiceList__Title">Discount minimum requirements</legend>
    <ul class="Polaris-ChoiceList__Choices">
      <li><label class="Polaris-Choice" for="PolarisRadioButton16"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton16" name="PolarisChoiceList8" type="radio" class="Polaris-RadioButton__Input" value="none" checked=""><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">None</span></label></li>
      <li><label class="Polaris-Choice" for="PolarisRadioButton17"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton17" name="PolarisChoiceList8" type="radio" class="Polaris-RadioButton__Input" value="minimum_purchase"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Minimum purchase</span></label></li>
      <li><label class="Polaris-Choice" for="PolarisRadioButton18"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton18" name="PolarisChoiceList8" type="radio" class="Polaris-RadioButton__Input" value="minimum_quantity"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Minimum quantity</span></label>
        <div class="Polaris-ChoiceList__ChoiceChildren">
          <div class="Polaris-Labelled--hidden">
            <div class="Polaris-Labelled__LabelWrapper">
              <div class="Polaris-Label"><label id="PolarisTextField2Label" for="PolarisTextField2" class="Polaris-Label__Text">Minimum Quantity</label></div>
            </div>
            <div class="Polaris-Connected">
              <div class="Polaris-Connected__Item Polaris-Connected__Item--primary">
                <div class="Polaris-TextField"><input id="PolarisTextField2" autocomplete="off" class="Polaris-TextField__Input" aria-labelledby="PolarisTextField2Label" aria-invalid="false" value="">
                  <div class="Polaris-TextField__Backdrop"></div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </li>
    </ul>
  </fieldset>
  <div id="PolarisPortalsContainer"></div>
</div>

Single-choice or multi-choice list with children content (only rendered when choice is selected)

マーチャントが選択肢の下にある追加コンテンツを見たり、操作したりする必要がある場合に使用します。このコンテンツは、選択肢が選択されたときにのみレンダリングされます。選択肢が一つしかないときと複数あるときの両方に対応しています。

React
React
function SingleOrMultuChoiceListWithChildrenContextWhenSelectedExample() {
  const [selected, setSelected] = useState(['none']);
  const [textFieldValue, setTextFieldValue] = useState('');

  const handleChoiceListChange = useCallback((value) => setSelected(value), []);

  const handleTextFieldChange = useCallback(
    (value) => setTextFieldValue(value),
    [],
  );

  const renderChildren = useCallback(
    (isSelected) =>
      isSelected && (
        <TextField
          label="Minimum Quantity"
          labelHidden
          onChange={handleTextFieldChange}
          value={textFieldValue}
          autoComplete="off"
        />
      ),
    [handleTextFieldChange, textFieldValue],
  );

  return (
    <div style={{height: '150px'}}>
      <ChoiceList
        title="Discount minimum requirements"
        choices={[
          {label: 'None', value: 'none'},
          {label: 'Minimum purchase', value: 'minimum_purchase'},
          {
            label: 'Minimum quantity',
            value: 'minimum_quantity',
            renderChildren,
          },
        ]}
        selected={selected}
        onChange={handleChoiceListChange}
      />
    </div>
  );
}
HTML
HTML
<div>
  <div style="height: 150px;">
    <fieldset class="Polaris-ChoiceList" id="PolarisChoiceList14" aria-invalid="false">
      <legend class="Polaris-ChoiceList__Title">Discount minimum requirements</legend>
      <ul class="Polaris-ChoiceList__Choices">
        <li><label class="Polaris-Choice" for="PolarisRadioButton34"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton34" name="PolarisChoiceList14" type="radio" class="Polaris-RadioButton__Input" value="none" checked=""><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">None</span></label></li>
        <li><label class="Polaris-Choice" for="PolarisRadioButton35"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton35" name="PolarisChoiceList14" type="radio" class="Polaris-RadioButton__Input" value="minimum_purchase"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Minimum purchase</span></label></li>
        <li><label class="Polaris-Choice" for="PolarisRadioButton36"><span class="Polaris-Choice__Control"><span class="Polaris-RadioButton"><input id="PolarisRadioButton36" name="PolarisChoiceList14" type="radio" class="Polaris-RadioButton__Input" value="minimum_quantity"><span class="Polaris-RadioButton__Backdrop"></span></span></span><span class="Polaris-Choice__Label">Minimum quantity</span></label></li>
      </ul>
    </fieldset>
  </div>
  <div id="PolarisPortalsContainer"></div>
</div>

Props

allowMultiple
boolean
マーチャントが一度に複数のオプションを選択できるようにする

choices(Required)
Choice[]
選択肢のコレクション

disabled
boolean
すべての選択肢を無効にする

error
string | ReactElement | (string | ReactElement)[]
エラーメッセージを表示する

name
string
フォーム入力用の名前

selected(Required)
string[]
厳選された選択肢のコレクション

title(Required)
React.ReactNode
選択肢のリストのラベル

titleHidden
boolean
タイトルの表示を切り替える

onChange
(selected: string[], name: string) => void
選択された選択肢が変更されたときのコールバック

アクセシビリティ

選択肢リストコンポーネントは、チェックボックスコンポーネントラジオボタンコンポーネントのアクセシビリティ機能を使用しています。

Android

シングルチョイスリスト

マーチャントがリストから 1 つのオプションを選択できるようにします。

  • 全てのオプションが、どちらか一方のみの選択であることを確認してください

エラー付きのシングルチョイスリスト

エラーメッセージとエラーのあるフィールドを結びつけることで、アクセス可能なエラー処理を可能にします。

マルチチョイスリスト

マーチャントがリストから複数のオプションを選択できるようにします。

  • どちらか一方しか選べない選択肢は避けてください。

アクセシビリティ

Android のアクセシビリティについては、Material Design と開発ドキュメントをご覧ください。

iOS

シングルチョイスリスト

マーチャントがリストから 1 つのオプションを選択できるようにします。

  • すべてのオプションが、どちらか一方のみの選択であることを確認してください。

エラー付きのシングルチョイスリスト

エラーメッセージとエラーのあるフィールドを結びつけることで、アクセス可能なエラー処理を可能にします。

マルチチョイスリスト

  • どちらか一方しか選べないオプションは避けてください。

アクセシビリティ

iOS のアクセシビリティについては、Apple の Human Interface Guidelines や API のドキュメントをご覧ください。

ベストプラクティス

選択肢のリストは以下のことに注意してください。

  • マーチャントが何をすべきか、または利用可能なオプションを説明するタイトルを含む
  • オプションが何をするものなのかを明確に表示する。
  • 複数選択が可能な場合、互いに排他的なオプションは避ける

コンテンツガイドライン

リストタイトル

リストタイトルは以下のことに注意してください

  • マーチャントがリスト内のアイテムがどのようにグループ化されているかを理解できるようにする、またはマーチャントがどのような選択をしているかを説明する。

  • 簡潔でスキャンしやすいこと
    • 一目見てわかるように、シンプルで明確な表現を使用する
    • リストタイトルは一文にとどめる
    • タイトルが直下のリストを示している場合は、コロンで終わること
    • 大文字小文字をくべるすること

  • コロンを使わない

選択肢リスト

選択肢リストのすべての項目は、以下の通りです。

  • 大文字で始まる

  • 各行の最後にカンマやセミコロンを使わない

  • 文語体(最初の単語は大文字、残りの単語は小文字)で書かれていること

ヘルパーテキストと説明文

リストにヘルパーテキストが含まれている場合、リストアイテムの下にある説明文にのみ句読点を入れる必要があります。

関連コンポーネント

Color picker

カラーピッカーは、マーチャントが視覚的に色を選択するためのものです。例えば、マーチャントはカラーピッカーを使って、ショップのメールテンプレートのアクセントカラーをカスタマイズします。

Default color picker

マーチャントが色を選択する必要があるときに使用して、視覚的に選択できるようにします。

React
React
function ColorPickerExample() {
  const [color, setColor] = useState({
    hue: 120,
    brightness: 1,
    saturation: 1,
  });

  return <ColorPicker onChange={setColor} color={color} />;
}
HTML
HTML
<div>
  <div class="Polaris-ColorPicker">
    <div class="Polaris-ColorPicker__MainColor">
      <div class="Polaris-ColorPicker__ColorLayer" style="background-color: rgb(0, 255, 0);"></div>
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(160px, 0px, 0px);"></div>
      </div>
    </div>
    <div class="Polaris-ColorPicker__HuePicker">
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(0px, 58.6667px, 0px);"></div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer"></div>
</div>

Colorpicker with transparent value

ビジュアルビルダーに接続されている場合に使用し、指定されたオブジェクトが透明な背景を持ち、下にあるオブジェクトが透けて見えるようにします。

React
React
function ColorPickerWithTransparentValueExample() {
  const [color, setColor] = useState({
    hue: 300,
    brightness: 1,
    saturation: 0.7,
    alpha: 0.7,
  });

  return <ColorPicker onChange={setColor} color={color} allowAlpha />;
}
HTML
HTML
<div>
  <div class="Polaris-ColorPicker">
    <div class="Polaris-ColorPicker__MainColor">
      <div class="Polaris-ColorPicker__ColorLayer" style="background-color: rgba(255, 0, 255, 0.7);"></div>
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(112px, 0px, 0px);"></div>
      </div>
    </div>
    <div class="Polaris-ColorPicker__HuePicker">
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(0px, 127.167px, 0px);"></div>
      </div>
    </div>
    <div class="Polaris-ColorPicker__AlphaPicker">
      <div class="Polaris-ColorPicker__ColorLayer" style="background: linear-gradient(to top, rgba(255, 77, 255, 0) 18px, rgb(255, 77, 255) calc(100% - 18px));"></div>
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(0px, 54.1px, 0px);"></div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer"></div>
</div>

Colorpicker with transparent value full width

ビジュアルビルダーに接続されている場合に使用し、指定されたオブジェクトが透明な背景を持ち、下にあるオブジェクトが透けて見えるようにします。

React
React
function ColorPickerWithTransparentValueExample() {
  const [color, setColor] = useState({
    hue: 300,
    brightness: 1,
    saturation: 0.7,
    alpha: 0.7,
  });

  return <ColorPicker fullWidth onChange={setColor} color={color} allowAlpha />;
}
HTML
HTML
<div>
  <div class="Polaris-ColorPicker Polaris-ColorPicker--fullWidth">
    <div class="Polaris-ColorPicker__MainColor">
      <div class="Polaris-ColorPicker__ColorLayer" style="background-color: rgba(255, 0, 255, 0.7);"></div>
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(473.2px, 0px, 0px);"></div>
      </div>
    </div>
    <div class="Polaris-ColorPicker__HuePicker">
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(0px, 127.167px, 0px);"></div>
      </div>
    </div>
    <div class="Polaris-ColorPicker__AlphaPicker">
      <div class="Polaris-ColorPicker__ColorLayer" style="background: linear-gradient(to top, rgba(255, 77, 255, 0) 18px, rgb(255, 77, 255) calc(100% - 18px));"></div>
      <div class="Polaris-ColorPicker__Slidable">
        <div class="Polaris-ColorPicker__Dragger" style="transform: translate3d(0px, 54.1px, 0px);"></div>
      </div>
    </div>
  </div>
  <div id="PolarisPortalsContainer"></div>
</div>

Props

allowAlpha
boolean
ユーザーがアルファ値を選択できるようにする

color(Required)

Object

alpha
type: number
透明度

brightness(Required)
type: number
色の明るさ

hue(Required)
type: number

saturation(Required)
type: number
色の彩度

Color
現在選択されている色

fullWidth
boolean
HuePicker が幅いっぱいに表示されるようにする

id
string
要素の ID

onChange(Required)
(color: HSBAColor) => void
色が選択された時のコールバック

ベストプラクティス

  • マーチャントが透明な色を選択できるようにするには、アルファスライダを使用します。

Shopify アプリのご紹介

Shopify アプリである、「商品ページ発売予告アプリ | リテリア Coming Soon」は、商品ページを買えない状態のまま、発売日時の予告をすることができるアプリです。Shopify で Coming Soon 機能を実現することができます。

https://apps.shopify.com/shopify-application-314?locale=ja&from=daniel

Shopify アプリである、「らくらく日本語フォント設定|リテリア Font Picker」は、ノーコードで日本語フォントを使用できるアプリです。日本語フォントを導入することでブランドを演出することができます。

https://apps.shopify.com/font-picker-1?locale=ja&from=daniel

Discussion

ログインするとコメントできます